References & integrity
datadata’s model is referential: schemas mark fields as references — to a record in the same document, to another document, or to a collaborative sub-document. Declaring them in the schema is what lets the engine enforce integrity (and, where it can, repair it) instead of leaving dangling ids to the application.
Declaring references
Section titled “Declaring references”A schema document marks fields as references. There are four kinds, each declared as such in the schema:
- Entity references point at a record inside the same document — for example, an edge in a diagram pointing at two nodes.
- Document references point at another document of a given type, within the same folder — the reference can’t reach across a folder boundary.
- Yjs references hold a handle to one of the document’s own collaborative sub-documents — a Yjs Y.Doc with its own CRDT sync lane and lifecycle.
- Blob references hold a handle to an immutable file — an image, a PDF — in the folder’s object store. See Blobs.
The first two are constraints over an ordinary id; a yjs reference and a blob reference are their own value kinds — handles to content held outside the JSON, not pointers into it.
Rules for entity references
Section titled “Rules for entity references”An entity reference also declares what should happen when its target goes away. Because the referrer and the target live in the same document, these rules are enforced within that document, at each write:
- restrict (the default) — the write is rejected while a referrer still points at the target, so you can’t delete a node while an edge needs it.
- cascade — deleting the target also drops the referrers that pointed at it.
- unreferenced — a target that loses its last referrer is reclaimed (reference-counted: the target lives only as long as something points at it).
An entity reference can also bound how many referrers a target must carry (for example, “at least one”). These rules make integrity a property of the schema rather than something each write path re-implements — a raw update gets the same cleanup as any other.
Checking and repairing
Section titled “Checking and repairing”How a reference is enforced depends on its kind — and the guarantees differ because the target lives in a different place each time:
- Entity references are both checked and repaired at every write. Because referrer and target live in the same document, this is atomic: the declared rules run first (cascade drops dangling referrers, unreferenced reclaims targets nothing points at, iterated to a fixpoint), then restrict and cardinality violations reject the write. The repaired state is the same whether the client applied it optimistically or the server applied it authoritatively, so sync converges.
- Yjs references are reference-counted. When a write leaves one of the document’s sub-documents with no referring field, that Y.Doc is deleted in the same write — no separate cleanup step. A reference to a sub-document that doesn’t exist yet is fine: it’s created lazily on first use.
- Blob references are reference-counted too, with the opposite creation rule: the bytes must exist first. A write naming a blob that was never uploaded, never finalized, or already swept is rejected, and the reference edge is recorded in the same transaction as the write — so a synced document never points at missing bytes. A blob whose last reference is removed is reclaimed by a later sweep, not inline; the lifecycle explains why.
- Document references point at another document within the same folder — the existence check resolves against the folder’s own registry, so a document reference can’t reach outside it. They are checked at write time only: the target must exist when the write lands, but there is no cross-document repair — a target deleted afterward leaves a dangling pointer, which surfaces the referrer as an invalid document rather than erroring. There’s no transaction spanning the two documents. Every validated write also records the document’s outbound references in a folder-level index, so the invalid-document enumeration derives dangling-reference invalidity from that index against the live document set — deleting a target lists its referrers instantly, and restoring it heals the listing just as instantly, with nothing persisted into the referrers that could go stale. Clients subscribed to a referrer see the same flip: deleting, restoring or creating the target sends them the referrer’s current state, flagged or cleared. The flag lists every broken reference, not just the first, each located at the field that holds the id and naming the rule and the missing id, so a repair can fix them all in one write.
This matters doubly for AI agents: an agent can validate the referential consistency of its staged changes before committing, and the rules it must respect are readable from the schema documents themselves.