✍ïļBlog / Technical

Why We Use SpacetimeDB (and What That Means for Your Data)

The reasoning behind choosing SpacetimeDB as Sproutcast's real-time backend.

5 min readSpacetimeDB, architecture, real-time, technical

When we were choosing a backend for the Sproutcast PWA, the requirements were specific:

1. Real-time subscription — the dashboard should update the moment a pipeline finishes, without polling

2. Self-hostable — users should be able to run the whole stack on a local network without a cloud account

3. Minimal backend code — we had already written the edge pipeline in C++ and a thin Go bridge; we did not want to maintain a third REST API

SpacetimeDB solves all three.

What SpacetimeDB is

SpacetimeDB is a database that runs application logic inside the database itself, as WebAssembly modules. The Sproutcast module (written in Rust, compiled to WASM) lives inside SpacetimeDB and defines six tables and thirteen reducers — think of reducers as stored procedures that clients can call directly over WebSocket.

The frontend connects via WebSocket and subscribes to SQL queries:

SELECT * FROM plant
SELECT * FROM analysis_result
SELECT * FROM notification

When a row changes, SpacetimeDB pushes the diff to every subscribed client immediately. The dashboard stays live without any polling logic.

Self-hosting

Because SpacetimeDB is a single binary with no external dependencies (no Postgres, no Redis), running your own Sproutcast server is:

docker compose up

The edge pipeline on your Raspberry Pi writes to NATS, the Go bridge translates NATS messages into SpacetimeDB reducer calls, and the PWA subscribes directly. Every component runs on your local network. Your data never touches our servers unless you choose the hosted cloud option.

The trade-off

SpacetimeDB is younger than Postgres. Its query planner is simpler. For Sproutcast's scale (tens to hundreds of plants per user, thousands of analysis rows per plant per year) it is more than sufficient. For a large research deployment monitoring thousands of plants in real time, you would want to benchmark it.

The WASM module constraint (all table definitions in a single file, deterministic reducers) takes some getting used to, but it enforces a clean architecture — no side effects, no external calls, no non-determinism. Your data model is the module; the module is auditable.