Realtime
Two primitives, one WebSocket, every insert/update/delete on your source.
subscribe— live tail of all matching rows. Yields every change to the lens, optionally filtered.observe— single-record watch. First yield is the current state; every subsequent yield is an update.
Both are AsyncIterables. Both ride the same shared WebSocket — one connection per environment, multiplexed across every live op.
How it reaches you
No polling. No long-poll fallback. One Postgres NOTIFY per ingested batch, fanned out by a connection pool on the service to every live subscriber.
When to use what
| Need | Reach for |
|---|---|
| Live tail of all changes (dashboards, activity feeds) | subscribe |
| Single-record state that updates in place (detail page) | observe |
| "New content" ticks for a ranked feed (no row payload) | feed.<name>.subscribe |
| Progressive results as a big query returns | stream.query / stream.search (chunked, not live — see Pagination & streaming) |
feed.subscribe is a different primitive — it yields FeedTickEvent
counts, not row payloads. Use it when you want "new stuff" signals for a
ranked list. Use subscribe when you want the row data itself.
Access rules
Live ops are gated by grants.stream:
enabled: false— disables all streaming on this lens.modes: ['chunked']— turns off live ops (subscribe/observe/feed.subscribe) but keepsstream.search/stream.query.maxLiveSubscriptions— per-lens cap on concurrent live subs. Combined with an org-level tier cap.
Filter on subscribe
subscribe accepts an optional filter (equality-only in v1):
No $-operator grammar here (unlike query.where) — the filter runs
in-process on every NOTIFY, so it's kept intentionally cheap. Complex
predicates are v0.2.
No auto-reconnect (v1)
If the WebSocket drops — server restart, network blip, laptop sleep —
the client iterator throws BeamStreamClosedError. You wrap in a retry:
React's useSubscribe / useObserve hooks wrap this retry loop for
you — see Subscribe.
Transparent reconnect is on the roadmap. When it ships, the pattern above will still work; the hook contract won't change.