SpacetimeDB Architecture Overview: Database, WASM Runtime, and Real-Time Networking
SpacetimeDB is a unified relational database, WebAssembly/JavaScript runtime, and real-time networking layer packaged into a single binary that runs modules in RAM with ACID durability via an append-only commit log.
This SpacetimeDB architecture overview examines how the clockworklabs/SpacetimeDB codebase combines these distinct systems into one platform. The design centers on a Host process that orchestrates independent database replicas, executes user logic inside sandboxed modules, and streams live updates to clients over persistent WebSocket connections.
Core Architectural Components
Host and HostController
The Host is the root server process capable of running multiple independent databases simultaneously. It owns the on-disk data directory, manages the thread pool for module execution, and hosts the metrics subsystem. The orchestration logic resides in crates/core/src/host/host_controller.rs, where the HostController struct handles the lifecycle of hosts, replica creation, module loading, hot-swap updates, and persistence integration.
Database (Replica)
Each logical application instance is a Database or Replica that maintains its own isolated in-memory state and persistent commit log. The implementation in crates/db/src/relational_db.rs provides the relational engine where all mutable table data resides in RAM for ultra-low latency access.
Modules and Runtime Engines
Business logic is packaged as a Module—a WASM blob or V8 JavaScript bundle compiled from Rust, C#, TypeScript, or C++. The module representation and entry points (__init__, reducers, procedures) are defined in crates/vm/src/program.rs.
SpacetimeDB supports two interchangeable runtime engines selected by the module’s HostType:
- Wasmtime: The WebAssembly runtime implementation located in
crates/host/src/wasmtime.rs - V8: The JavaScript/TypeScript runtime implementation located in
crates/host/src/v8.rs
Tables, Reducers, Procedures, and Views
Within a module, developers define:
- Tables: SQL-style structures storing all state in RAM (documented in
docs/versioned_docs/version-1.12.0/00100-intro/00100-getting-started/00400-key-architecture.md) - Reducers: RPC-style functions that mutate tables inside single ACID transactions
- Procedures: I/O-capable functions (e.g., HTTP requests) that manage their own transaction boundaries
- Views: Read-only computed data that clients can subscribe to for live updates
Client SDKs and Identity
Language-specific Client SDKs (TypeScript, Rust, C#, C++) open WebSocket connections to the Host, authenticate an Identity, and expose generated stubs for tables, reducers, procedures, and views. The underlying API implementation is in crates/client-api/src/lib.rs.
Commit Log and Durability
All mutations append to an on-disk Commit Log (spacetimedb_commitlog) managed by the durability layer in crates/durability/src/lib.rs. On restart, the system replays this log to reconstruct the exact in-memory state, providing the speed of RAM with the durability of a write-ahead log.
Subscription Manager
The Subscription Manager in crates/subscription/src/module_subscription_manager.rs tracks which clients subscribe to which tables or views and pushes incremental delta updates over WebSocket connections whenever data changes.
Energy Metering
To protect against runaway computation, the Energy system in crates/energy/src/lib.rs implements a lightweight gas-like quota. Every reducer call consumes a bounded amount of Energy; the system aborts execution if the quota is exhausted.
Scheduler
The Scheduler in crates/scheduler/src/lib.rs handles periodic or repeating reducers, enabling "tick" logic and time-based events within a replica.
Data Flow and Lifecycle
The following sequence describes how a module becomes a live, reactive database:
-
Publish: The developer runs
spacetime publish <module>; the CLI uploads the compiled WASM/JS bundle to the Host. -
Instantiation: The
HostControllercreates aHost(if not already running) and aReplicafor the database. -
Module Loading: The
ModuleHostloads the appropriate runtime (Wasmtime or V8) and instantiates the module. -
Initialization: The module’s
__init__reducer runs to create tables and seed initial data. -
Client Connection: Clients connect via the SDK, receive an
Identity, and open a WebSocket. -
Transaction Execution: Calls to reducers are serialized into a transaction, mutate in-memory tables, and append to the commit log.
-
Live Updates: When a table changes, the Subscription Manager pushes delta updates to all subscribed clients, including derived view updates.
-
Recovery: On host shutdown or crash, the commit log replays to rebuild the exact in-memory state, guaranteeing ACID semantics.
Code Examples
Defining Tables and Reducers in Rust
#[spacetimedb::table(name = players, public)]
pub struct Player {
#[primary_key]
#[auto_inc]
id: u64,
name: String,
score: i32,
user: Identity,
}
#[spacetimedb::reducer]
pub fn set_score(ctx: &spacetimedb::ReducerContext, id: u64, score: i32) {
ctx.db.players().update(|row| row.id == id, |row| row.score = score);
}
Source pattern documented in 00100-key-architecture.md and compiled by crates/vm/src/program.rs.
TypeScript Client Integration
import { useTable, useReducer } from "spacetimedb/client";
function Chat() {
const [players] = useTable(tables.player);
const setScore = useReducer(reducers.setScore);
const onScore = (id: bigint, pts: number) => setScore(id, pts);
return (
<ul>
{players.map(p => (
<li key={p.id.toString()}>
{p.name} – {p.score}
<button onClick={() => onScore(p.id, p.score + 1)}>+1</button>
</li>
))}
</ul>
);
}
Source: Generated client API in crates/client-api/src/lib.rs.
Manual Host Creation (Advanced)
use spacetimedb::host::HostController;
use spacetimedb::paths::server::ServerDataDir;
use std::sync::Arc;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let data_dir = Arc::new(ServerDataDir::new("./data"));
let controller = HostController::new(
data_dir,
Default::default(), // DB config
Default::default(), // program storage
Arc::new(spacetimedb::energy::NullEnergyMonitor),
Arc::new(spacetimedb::persistence::NullProvider),
Default::default(), // job cores
);
// Host now ready to accept publish / client connections.
// In practice the `spacetime` CLI calls the same path.
Ok(())
}
Source: Construction logic in crates/core/src/host/host_controller.rs.
Summary
- SpacetimeDB merges a relational database, WASM/JavaScript runtime, and real-time networking into one binary according to the
clockworklabs/SpacetimeDBsource code. - The HostController in
crates/core/src/host/host_controller.rsorchestrates multiple database replicas, each maintaining in-memory state backed by the Commit Log incrates/durability/src/lib.rs. - Modules execute in either Wasmtime or V8 runtimes, defined in
crates/host/src/wasmtime.rsandcrates/host/src/v8.rs, with logic represented incrates/vm/src/program.rs. - Reducers provide ACID transactions while Views enable reactive client subscriptions managed by the Subscription Manager in
crates/subscription/src/module_subscription_manager.rs. - The Energy system in
crates/energy/src/lib.rsprevents resource exhaustion by metering computation quotas per call.
Frequently Asked Questions
What is the difference between a Host and a Database in SpacetimeDB?
The Host is the top-level server process that can run many independent databases simultaneously, owning shared resources like the thread pool and data directory. A Database (or Replica) represents one logical application instance containing isolated in-memory tables and its own commit log. The Host manages the lifecycle of these replicas through the HostController, as implemented in crates/core/src/host/host_controller.rs.
How does SpacetimeDB ensure durability if all data is in RAM?
SpacetimeDB persists every mutation to an append-only Commit Log on disk, implemented in crates/durability/src/lib.rs. When the system restarts, it replays this log to reconstruct the exact in-memory state, providing the performance benefits of RAM storage with the crash-recovery guarantees of a write-ahead log.
What runtime environments does SpacetimeDB support for modules?
SpacetimeDB supports two interchangeable runtimes selected by the module's HostType: Wasmtime for WebAssembly modules (located in crates/host/src/wasmtime.rs) and V8 for JavaScript/TypeScript modules (located in crates/host/src/v8.rs). Both runtimes execute within the ModuleHost sandbox defined in crates/vm/src/program.rs.
How does the Energy system protect the host from infinite loops?
The Energy system, found in crates/energy/src/lib.rs, implements a gas-like quota that bounds the computation cost of each reducer call. The runtime decrements Energy units during execution and aborts the call if the quota is exhausted, preventing runaway modules from consuming excessive Host resources.
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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →