Portable event streams
The event log is more than audit. It’s designed so that a folder’s history can be consumed somewhere else — a replica, a pipeline, another system — with guarantees that are deliberately narrow and therefore easy to honor.
The guarantees
Section titled “The guarantees”Per-document, per-lane total order. A document’s history is two append-only streams, one per sync lane: the JSON patch events ordered by sequence number, and the Yjs update events in their own log order. Replaying the JSON patches in order reconstructs every state the structured data has ever had; folding the Yjs events reconstructs each embedded Y.Doc. A document export ships both streams, and an import replays each in order.
An exported Yjs event carries no number at all. Order is the only thing the Yjs log’s numbering ever meant — replay folds by order, and only across a delete-then-recreate of the same Y.Doc does even that matter — so the array carries it, and the importing store assigns its own. Nothing in the stream is a number the importer must honour, which is what makes it portable.
No cross-document ordering — on purpose. datadata does not guarantee any event ordering between documents. That sounds like a weakness; it’s the property that makes the streams portable. Each document’s stream is self-contained: you can fetch it, ship it, and apply it without knowing anything about any other document in the folder, and replicas can consume documents independently, at different paces, without coordination.
Every event is tagged with its schema version. Each event records the
sequence of the governing sys:schema:<type> document in effect when it was
written. And since schemas are documents,
the schema’s own history is also an event stream. Sync a document’s stream
plus its schema document’s stream, and a remote location can interpret every
historic version of the document with the exact schema it conformed to — a
complete, semantically meaningful picture of the data over time, reconstructed
with no access to the origin.
Migration events are ordinary events. When schema evolution rewrites a document on read, the rewrite is appended to the stream as a normal patch event. A consumer replays it like any other change — it doesn’t need to implement the migration engine to follow along.
The folder boundary
Section titled “The folder boundary”The schema version recorded on an event is the schema document’s sequence within its folder — a folder-local coordinate, not a global schema identity. There is no global schema timeline that every folder re-coordinatizes: a schema may evolve through versions A → B → C in source code, but a folder whose first boot upserted C directly has no record of A or B at all — each folder holds only the slice of the evolution it actually lived through, and two folders can hold different, incomplete slices.
Within a folder this is fully consistent: every event’s stamp resolves against that folder’s own schema history, so a folder’s streams are always coherent with each other. Portability is designed around that boundary. A whole folder (document streams plus schema-document streams) replays faithfully, and so does part of one — a subset of documents together with the schema documents they depend on, imported schema-first into a target that holds no independent history for those types.
Moving a document into a folder whose schema evolved on its own is what datadata is not designed for, and import fails safely at that boundary. It validates content, at the right coordinate: the target folder’s schema document is replayed to the imported document’s conformed sequence, and the document’s reconstructed snapshot must validate against that historic schema. A faithful same-lineage export always passes — a stored snapshot conforms to the sequence it’s stamped with, even a document that has become invalid against the current schema — so a rejection means the events were produced under a schema the target folder never held, and the import is refused even when the two folders’ sequence spaces happen to overlap. An explicit relaxed mode accepts the document anyway (the replay is still faithful); its first read then flags it invalid like any other non-conforming document. Relaxed even covers a document stamped beyond the target’s schema history — it is checked against the newest schema the target holds instead. Only a type with no resolvable schema at all is always refused: that document could never be read. Making cross-folder transfer actually work remains a remap problem (match reconstructed schema content, not sequence numbers), and no remap tool exists yet.
Purge’s guarantee stops at the folder boundary: it destroys this folder’s copy and releases the id — it cannot recall exports already taken. An export from before the purge still replays faithfully, and importing it afterwards is not a resurrection to refuse: it is an ordinary create of a new document under a freed id.
What this enables
Section titled “What this enables”- Read replicas and mirrors — feed a folder’s documents into another system, region, or store by tailing per-document streams.
- Analytics and pipelines — events are inspectable JSON patches with schema context, not opaque blobs.
- Point-in-time reconstruction — any historic version of any document, with the schema that governed it.
What this is not
Section titled “What this is not”This is replication, not offline sync: a one-way replay of server-confirmed history. Authority stays with the folder’s server — a replica can’t write events of its own and reconcile later — a replica is read-only. That’s a different mechanism from a disconnected client catching up: offline client writes replay from the client’s own queue on reconnect — the JSON lane last-writer-wins, the Yjs lane merged by CRDT — and that queue can outlive a reload. This page describes how confirmed history travels.