Skip to content

Documents & folders

A document is the unit of data:

  • docId — a string id, unique within its folder.
  • type — a string naming the document type; if a schema document exists for that type, writes are validated against it.
  • sequence — a monotonically increasing number assigned by the server on every accepted change. Sequences order changes and anchor guards and staged sessions.
  • data — the JSON payload. Rich text fields hold references to embedded Yjs documents rather than raw text.

A folder is the unit of synchronization and authority: one server instance owns one folder, orders all of its events, and broadcasts to all of its subscribers. In the current deployment a folder maps to one Cloudflare Durable Object.

Clients subscribe per document, not per folder — a client only receives changes for documents it has subscribed to.

Collections inside documents are stored as records keyed by id, with each record carrying a fractional index for ordering, rather than as JSON arrays. This is deliberate: JSON Patch addresses array elements by position, which is unstable when several writers insert and remove concurrently. Fractional indices make “insert between A and B” a single-key write that doesn’t disturb neighbors. (This is one of the workarounds discussed in JSON Patch RFC issues.)

Deletion is soft: a deleted document leaves the index and every read path, but its row, event log, and embedded Yjs state are retained, so it can be restored. Delete is a lifecycle change, recorded in the folder’s membership log rather than the document’s own event log — restoring a document returns it at the exact sequence it left, history intact.

Deletion is also observable. Live subscribers are pushed a doc:deleted event the moment a delete commits (an open editor can show “this document was deleted” instead of silently going stale), and subscribing to an already-deleted document answers doc:deleted too — deliberately distinct from “never existed”. Subscriptions survive the deletion, so a restore pushes the document straight back to everyone who was watching.

A deleted document still owns its id: creating a new document under a deleted docId is rejected with a distinct deleted error (restore it, or pick a new id) rather than the benign already-exists signal.

Two carve-outs: sys: documents — including schema documents — can’t be deleted, and hard deletion (purge) is designed but not implemented yet; see Limitations.

The engine maintains a few documents itself, readable like any other:

  • sys:index — lists every live document in the folder with its type.
  • sys:trash — lists every soft-deleted document (id, type, when); the data source for a trash/restore UI. Subscribe to it and it updates live as documents are deleted and restored.
  • sys:schema:<type> — the schema for a document type (schemas are documents).
  • sys:session / sys:stage:<docId> — synthesized views of staged work.