Persistence
Persistence means storing the editor's state to a database and restoring it later. The simplest option is the persistenceKey prop, which saves to the browser automatically. Snapshots and the store prop give you more control, and migrations bring old data up to date.
Local persistence
The simplest approach is the persistenceKey prop. This automatically saves the document and any uploaded assets to IndexedDB and syncs across browser tabs:
import { Tldraw } from 'tldraw'
import 'tldraw/tldraw.css'
export default function App() {
return (
<div style={{ position: 'fixed', inset: 0 }}>
<Tldraw persistenceKey="my-document" />
</div>
)
}Each unique key represents a separate document. Two editors with the same key share the same document and stay synchronized.
Snapshots
For custom storage backends, use getSnapshot and loadSnapshot to save and restore editor state as JSON:
import { getSnapshot, loadSnapshot } from 'tldraw'
// Save
const { document, session } = getSnapshot(editor.store)
await saveToDatabase(document)
// Load
const saved = await loadFromDatabase()
loadSnapshot(editor.store, { document: saved })The snapshot has two parts: document (shapes, pages, bindings) which you typically save to a server, and session (camera, selection, UI state) which you keep per-user locally. Loading a snapshot replaces the current document.
To load a snapshot once on startup, pass it to the snapshot prop of <Tldraw> instead. See Persistence for complete coverage of snapshots, async loading with TLStoreWithStatus, and auto-save patterns.
The store
The editor's store is a reactive database that holds all records. You can create a standalone store with createTLStore, load data into it, and pass it to the editor:
import { useState } from 'react'
import { createTLStore, loadSnapshot, Tldraw } from 'tldraw'
export default function App() {
const [store] = useState(() => {
const store = createTLStore()
const saved = localStorage.getItem('my-drawing')
if (saved) {
loadSnapshot(store, JSON.parse(saved))
}
return store
})
return <Tldraw store={store} />
}See Store for details on store operations, listening to changes, queries, and transactions.
Multiplayer sync
For real-time collaboration, use the @tldraw/sync package and its useSyncDemo hook. Multiple users can edit the same document simultaneously, see each other's cursors, and follow each other's viewports:
import { useSyncDemo } from '@tldraw/sync'
import { Tldraw } from 'tldraw'
export default function App() {
const store = useSyncDemo({ roomId: 'my-room-id' })
return <Tldraw store={store} />
}See Collaboration for production setup, custom presence, authentication, and building custom sync solutions.
Migrations
When you load a snapshot from an older schema version, the store migrates it automatically. For custom shapes, you can define migrations to handle changes to their props over time.
See Persistence for details on shape props migrations and general migrations.
Examples
- Persistence key — Automatic local persistence with a single prop
- Snapshots — Saving and loading editor state
- Local storage — Custom persistence with throttled auto-save
- Store events — Listening to store changes
- Shape with migrations — Migrations for custom shape props