Skip to content

Realtime

Copy page

Realtime in Nizhal is a hint to re-pull — not a data channel. The cursor pull is authoritative.

mutator commit → RealtimeAdapter.publish(bucketKey) → WS frame → client → echo.pull()
  • publish runs only from the server commit chokepoint
  • Payload is the bucket key only — no row data on the wire (no leak surface)
  • Client subscribes via GET /sync/stream (WebSocket) or a swappable transport

If a ping is missed (sleep, partition, DO idle), the next pull still converges. Set pull.intervalMs on createNizhalClient for a periodic fallback when realtime is unavailable.

AdapterImportUse case
inProcessRealtime@nizhal/server/adaptersDefault single-process pub/sub
listenNotifyRealtime@nizhal/server/adaptersMulti-instance Postgres via LISTEN/NOTIFY
cloudflareRealtime@nizhal/server/adapters/cloudflareWorkers + Durable Objects (PartyServer)
cloudflareHttpRealtime@nizhal/server/adapters/cloudflareHTTP long-poll fallback on Workers

All implement RealtimeAdapter: publish(bucket) + subscribe(onPing).

Default client transport uses PartySocket-compatible reconnect semantics against whichever adapter you deploy.

/sync/stream supports track / untrack with heartbeat timeout. State and diffs are bucket-scoped — presenceState, onPresence on the client.

Presence is orthogonal to data sync: it does not replace pull for row convergence.

Native WebSockets via @nizhal/react-native (nitroWebSocketSource) send Authorization on the upgrade header. NetInfo-based reactNativeOnlineDetector flushes the outbox on reconnect. See React Native.

If the client cursor is corrupt or far in the future, pull returns cursorReset: true and the collection re-bootstraps from cursor 0.