SpacetimeDB Networking and Communication Protocols: A Complete Technical Guide

SpacetimeDB uses WebSocket connections (v1 binary BSATN or text JSON, plus v2 for event tables), HTTP APIs for stateless reducer calls, and PostgreSQL wire protocol compatibility to enable real-time database subscriptions and client communication.

SpacetimeDB provides a rich set of network-enabled APIs that let clients, services, and tools communicate with a running database instance. According to the clockworklabs/SpacetimeDB source code, the architecture supports multiple protocols optimized for different use cases, from real-time game clients to standard SQL tooling.

WebSocket Protocol Architecture

The primary communication channel for SpacetimeDB is WebSocket, designed to handle bidirectional real-time updates, reducer calls, and subscription management over a persistent connection.

WebSocket v1 Binary (BSATN)

The binary WebSocket protocol uses the subprotocol identifier v1.bsatn.spacetimedb and encodes messages using BSATN (Binary Spacetime Algebraic Notation). This is the most efficient format for production use.

The low-level plumbing lives in sdks/rust/src/websocket.rs, which implements the Tokio/Tungstenite connection, message framing, compression, and reconnection logic. The binary protocol constant is defined in crates/client-api-messages/src/websocket/v1.rs:

// From crates/client-api-messages/src/websocket/v1.rs
pub const BIN_PROTOCOL: &str = "v1.bsatn.spacetimedb";

WebSocket v1 Text (SATS-JSON)

For debugging or language runtimes without binary support, the text protocol v1.json.spacetimedb uses SATS-JSON encoding. The same websocket.rs module handles both formats, switching the message encoder based on the selected subprotocol during the handshake.

WebSocket v2 for Event Tables

Introduced in SpacetimeDB 2.0, the v2 protocol supports event tables and a streamlined message model. The v2 message types are defined in client-api-messages/src/websocket/v2.rs, providing enhanced capabilities for complex subscription patterns.

Connection Lifecycle and Identity

When a client opens a WebSocket connection via GET /v1/database/<module>/subscribe, the server creates a connection instance identified by a ConnectionId that persists for the session duration.

Two logical channels share the same TCP socket:

  • Request/Response – Client-initiated calls such as CallReducer and Subscribe
  • Push – Server-initiated subscription updates, row changes, and event table notifications

The subscription semantics, including ordering guarantees and message channel behavior, are documented in docs/versioned_docs/version-1.12.0/00200-core-concepts/00400-subscriptions/00200-subscription-semantics.md.

Lifecycle reducers client_connected and client_disconnected run once per connection, providing module authors with hooks into connection events as documented in docs/static/llms.md.

HTTP Database API for Stateless Operations

For one-off procedural calls and token-based authentication, SpacetimeDB exposes an HTTP API that mirrors WebSocket functionality for simple cases:


# Subscribe endpoint upgrades to WebSocket

GET /v1/database/:name_or_identity/subscribe

# Invoke a reducer statelessly

POST /v1/database/:name_or_identity/reducer

# One-shot database dump

GET /v1/database/:name_or_identity/snapshot

Headers such as Authorization: Bearer <token> and Sec-WebSocket-Protocol are defined in the HTTP API documentation at docs/versioned_docs/version-1.12.0/00300-resources/00200-reference/00200-http-api/00300-database.md.

PostgreSQL Wire Protocol Compatibility

SpacetimeDB implements the native PostgreSQL wire protocol, allowing standard psql clients or any PostgreSQL driver to connect directly. The server acts as a thin wrapper around the same subscription engine, translating PG messages into internal WebSocketMessage types.

The implementation entry point resides in crates/pg/src/pg_server.rs, utilizing the pgwire crate for protocol handling:

psql "host=localhost port=5432 dbname=my_module user=spacetimedb"

Internal RPC and Subscription Mechanics

Beyond client-facing protocols, SpacetimeDB uses a custom RPC system for internal communication between the host and database instances. This handles subscription management, metrics collection, and intra-process message passing.

The subscription message handling and ordering guarantees are implemented in crates/core/src/subscription/*, while network traffic metrics—including WebSocket request/response counts, payload sizes, and compression timings—are tracked in crates/core/src/worker_metrics/mod.rs.

Client SDK Implementation Patterns

All language SDKs abstract the low-level protocol details while exposing consistent APIs for connection management.

Rust SDK Connection Handling

The Rust SDK in sdks/rust/src/websocket.rs spawns a background Tokio task running WsConnection::connect. The DbConnection object exposes subscribe, call_reducer, and event callbacks while handling automatic reconnection and compression negotiation (supporting none, deflate, and zstd via sdks/rust/src/compression.rs).

TypeScript and Game Engine SDKs

The TypeScript SDK leverages the browser's native WebSocket API with automatic compression negotiation. Unity and Unreal SDKs wrap the low-level socket in engine-friendly components, advancing the connection each frame to process incoming messages.

Summary

  • WebSocket protocols (v1.bsatn.spacetimedb, v1.json.spacetimedb, and v2) provide real-time bidirectional communication for subscriptions and reducer calls, implemented in sdks/rust/src/websocket.rs and crates/client-api-messages/src/websocket/.
  • HTTP API offers stateless endpoints for reducer invocation and snapshots, documented in the HTTP Database API reference.
  • PostgreSQL wire protocol compatibility allows standard SQL tools to connect via crates/pg/src/pg_server.rs.
  • Internal RPC handles subscription management and metrics in crates/core/src/subscription/ and crates/core/src/worker_metrics/mod.rs.
  • Compression (deflate, zstd) and connection lifecycle reducers (client_connected, client_disconnected) provide production-ready optimization and hooks.

Frequently Asked Questions

What protocol does SpacetimeDB use for real-time updates?

SpacetimeDB uses WebSocket connections as the primary protocol for real-time updates. Clients can choose between the binary v1.bsatn.spacetimedb format for efficiency or v1.json.spacetimedb for debugging. Version 2 of the protocol introduces enhanced support for event tables and streamlined message models in SpacetimeDB 2.0.

How does SpacetimeDB handle compression in WebSocket connections?

The Rust SDK in sdks/rust/src/compression.rs automatically negotiates compression during the WebSocket handshake, supporting none, deflate, and zstd algorithms. Compression is applied per-message to reduce bandwidth for subscription updates and reducer calls. Metrics for compression timing and payload sizes are tracked in crates/core/src/worker_metrics/mod.rs.

Can I use standard PostgreSQL tools with SpacetimeDB?

Yes, SpacetimeDB implements the native PostgreSQL wire protocol in crates/pg/src/pg_server.rs, allowing you to connect using standard tools like psql, pgAdmin, or any PostgreSQL driver. The server translates PG messages into internal WebSocket messages, enabling SQL queries against your module's tables while maintaining compatibility with existing database tooling.

What is the difference between BSATN and SATS-JSON formats?

BSATN (Binary Spacetime Algebraic Notation) is the binary encoding used by the v1.bsatn.spacetimedb WebSocket subprotocol, offering compact, efficient serialization for production use. SATS-JSON is the text-based JSON encoding used by v1.json.spacetimedb, defined in the same protocol files but human-readable for debugging or environments without binary support. Both formats are handled by the SDK's websocket.rs module, which switches encoders based on the negotiated subprotocol.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →