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:

Tables, Reducers, Procedures, and Views

Within a module, developers define:

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:

  1. Publish: The developer runs spacetime publish <module>; the CLI uploads the compiled WASM/JS bundle to the Host.

  2. Instantiation: The HostController creates a Host (if not already running) and a Replica for the database.

  3. Module Loading: The ModuleHost loads the appropriate runtime (Wasmtime or V8) and instantiates the module.

  4. Initialization: The module’s __init__ reducer runs to create tables and seed initial data.

  5. Client Connection: Clients connect via the SDK, receive an Identity, and open a WebSocket.

  6. Transaction Execution: Calls to reducers are serialized into a transaction, mutate in-memory tables, and append to the commit log.

  7. Live Updates: When a table changes, the Subscription Manager pushes delta updates to all subscribed clients, including derived view updates.

  8. 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

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:

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 →