Appearance
Storage Backends
Document-store separates writes from reads. The persistence layer handles writes — storing documents, rendering the latest state, and maintaining the change log for sync. For reads, you query your database directly.
Supported backends
| Backend | Best for | Package |
|---|---|---|
| SurrealDB | Embedded or distributed, multi-model queries | surrealdb + @surrealdb/node |
| SQLite | Desktop apps, CLI tools, simple embedded | better-sqlite3 |
| MongoDB | Server deployments, large datasets | mongodb |
How storage works
The persistence layer manages three concerns:
1. Change log
Raw CBOR documents for P2P sync. Every add() and edit() is logged here. Peers exchange these during sync.
2. Document store
Internal document state — used by the store to compute edits and validate writes.
3. Rendered tables
The latest version of each document, ready for your app to query. One table/collection per document type. This is what you read from.
add('bookmark', { uid, url, title })
│
├──► change log (CBOR for sync)
├──► document store (internal state for edits)
└──► bookmark ◄── your app reads thisChoosing a backend
SurrealDB is the recommended default. The embedded SurrealKV engine is file-backed with no server to manage — same deployment simplicity as SQLite, but with a much richer query language. Relations, graph traversals, record links, full-text search, and native binary types. Scales from embedded to distributed without changing your queries.
SQLite if you want the simplest possible setup or need raw SQL compatibility. Single file, synchronous API, battle-tested. Good for CLI tools and small apps where you don't need relational queries across document types.
MongoDB if you're running a server with multiple users or need horizontal scaling. Use the MongoDB driver directly for reads.
Something else? See Custom Backend for how to write your own persistence layer.