Learn · Shared context

State documents

Keep current JSON values with merge patches, versions, and explicit concurrency checks.

A state document is a versioned JSON value addressed by a key inside the room. Use it for shared current values such as preferences or the active task context. Use an event when the durable fact itself is the product record.

Patch a current value

TypeScript
// room has state:write on preferences. Zero expects no existing document.
const initial = await room.patchState("preferences", {language: "en"}, 0);
const updated = await room.patchState(
  "preferences",
  {language: "fr", obsoleteSetting: null},
  initial.version,
);
console.log(updated.version, updated.value);

Patches use JSON merge-patch behavior: object fields merge recursively, null removes a field, and arrays or scalar values replace the old value. A successful mutation increments the version and produces a durable state.patched event.

Protect the intent of a write

Supply expectedVersion when the write depends on an earlier read. If two clients edit version 1, only a write still matching that version can succeed. The other client must read current state and reconcile its intent. Repeating the stale expected version does not resolve a conflict.

Two clients read preferences version 1. Client A submits a patch expecting version 1 and the room commits version 2. Client B then submits a patch still expecting version 1 and receives a version conflict. Client B must read the newer value and reconcile before another versioned write.
The expected version protects a read-dependent write from silently overwriting newer shared context.Open SVG ↗Excalidraw source ↓

Omitting expectedVersion skips that optimistic concurrency check. Each SDK patchState() call generates a fresh client event ID, so repeating the method after an uncertain response is not the same retry primitive as reusing a publication ID.

Hydrate and follow updates

A new view can read current state from a snapshot and then follow changes. Apply only newer versions for each key so replay does not overwrite a more recent value. The hydration pattern covers the snapshot/subscription handoff.

State access and event access are separate. Hydration needs state:read on the document key; updates need event:subscribe on state.patched, with visibility still enforced. That channel-less event grant is type-wide, not a document-key filter. Validate the payload and select the keys your view owns.

Read state types, versioned storage and merge behavior, and store tests. For an identified deliverable with a type and status, use an artifact.

Search the documentation

Type to search all guides.

Diagram

100%Open original ↗