Conat DKV and PubSub — When to Use What
Overview
CoCalc has two conat-based primitives for sharing ephemeral state between clients:
| Feature | PubSub | DKV (Distributed Key-Value) |
|---|---|---|
| Delivery | Fire-and-forget | Eventually consistent |
| Late joiners | Miss events | Read current state on init |
| Persistence | None | In-memory on hub (ephemeral) or persistent |
| Use case | Cursor positions, transient notifications | Shared state that new clients need to see |
| API | set(obj) / on("change", cb) | set(key, val) / get(key) / on("change", cb) |
Rule of thumb: If a client that opens the file 30 seconds later needs to see the state, use DKV. If it's purely transient (like cursor flickers), use PubSub.
DKV (Distributed Key-Value Store)
Import and Create
From the frontend, dkv is also available via webapp_client.conat_client.dkv().
Core API
Key Behaviors
set()is synchronous — local state updates immediately, readable viaget()right away.changeevent fires for all server-confirmed data — including echoes of your own writes. When your own write round-trips through the server and matches local state, the local copy is discarded but thechangeevent still fires. Handlers must be idempotent.Reference counting — same
(name, scope)returns the same cached instance.close()decrements the ref count; truly closes when all refs are released.Conflict resolution — default is last-write-wins. Custom merge functions available via the
mergeoption.
Frontend Usage Pattern (in class-based Actions)
Frontend Usage Pattern (in React hooks)
Options Reference
PubSub
Import and Create
Core API
Key Behaviors
Fire-and-forget — no delivery guarantee. Late joiners miss all prior messages.
Self-echo — you receive your own messages back. Must guard against re-entry.
No persistence — there's no
get(). State exists only in the stream of events.Synchronous constructor — subscribes internally (no async init needed).
Existing Usage Examples
| Feature | Primitive | Scope | Key | File |
|---|---|---|---|---|
| Explorer settings | DKV | account | project_id | frontend/project/explorer/use-explorer-settings.ts |
| Search history | DKV | account | project_id | frontend/project/explorer/use-search-history.ts |
| Starred files | DKV | account | project_id | frontend/project/page/flyouts/store.ts |
| Build coordination | DKV | project | file path | frontend/frame-editors/generic/build-coordinator.ts |
| Cursor positions | PubSub | project+path | — | conat/sync/pubsub.ts |
Implementation Details
Source:
packages/conat/sync/dkv.ts(DKV),packages/conat/sync/pubsub.ts(PubSub)Frontend client:
packages/frontend/conat/client.tsline 484 (dkv = dkv)Tests:
packages/backend/conat/test/sync/dkv.test.ts,dkv-basics.test.ts