Skip to content

Subscriptions

SpacetimeDB: Subscriptions ↗

Subscriptions are scoped native resources. A session can subscribe to public tables and event tables, then release each subscription when the scope exits or the handle is unsubscribed.

const program = Effect.gen(function* () {
const session = yield* Example.client.ws.Session
yield* session.subscribe(Example.targets.allPublicTables())
yield* session.streamEventTable("presenceEvent").pipe(Stream.runDrain)
})

Each subscribe call opens its own native SpacetimeDB query set on the session connection. allPublicTables() remains one native multi-query subscription.

Persistent-table streams use bounded callback queues by default and should be treated as invalidation signals: re-read the authoritative session cache when a change arrives. Event-table streams are raw event feeds and are unbounded unless you opt into a bounded buffer and accept lossy overflow behavior.

The session stream helper family covers the common shapes:

HelperUse
streamTable(key, options?)Persistent-table insert/update/delete signals.
streamRows(key)Initial snapshot followed by cache snapshots after table changes.
tableGroup(keys, options?)Multi-table snapshot group with subscribe, readSnapshot, and changes.
streamTableEvents(key, options?)Persistent-table changes with decoded StdbEventContext.
streamEventTable(key, options?)Event-table insert feed.
streamTarget(target, options?)Stream a projected subscription target.

Persistent-table streams accept { buffer: { bufferSize, strategy } }, where strategy is "sliding" or "dropping". The default is a bounded sliding queue sized for cache invalidation signals. Event-table streams accept { buffer: { bufferSize } }; overflowing that buffer fails the stream with EventTableStreamOverflowError rather than silently dropping events.

Event tables use native delivery semantics. Every live native query set that covers an event can deliver that event, so subscribe once at an app state boundary and fan out from that stream when a domain needs one event-processing path.

tableGroup(keys).changes emits an initial snapshot and then burst-coalesced snapshots by re-reading the generated client’s authoritative cache.

streamTableEvents decodes native generated-client event metadata into StdbEventContext. Use decodeStdbEventContext from effect-spacetimedb/client when you are working with lower-level generated callbacks yourself.

import * as Effect from "effect/Effect"
import * as StdbClient from "effect-spacetimedb/client"
declare const rawContext: unknown
const decoded = StdbClient.decodeStdbEventContext(rawContext).pipe(
Effect.map((context): StdbClient.StdbEventContextType => context),
)

Subscription setup failures are routed into the stream queue explicitly so rejected subscriptions, invalidated connections, and transport errors do not turn into streams that simply never emit.