spacetimedb-concepts

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

SpacetimeDB Core Concepts

SpacetimeDB核心概念

SpacetimeDB is a relational database that is also a server. It lets you upload application logic directly into the database via WebAssembly modules, eliminating the traditional web/game server layer entirely.

SpacetimeDB是一款兼具服务器功能的关系型数据库。它允许你通过WebAssembly模块将应用逻辑直接上传至数据库中,彻底省去了传统的Web/游戏服务器层。

Critical Rules (Read First)

重要规则(请先阅读)

These five rules prevent the most common SpacetimeDB mistakes:
  1. Reducers are transactional — they do not return data to callers. Use subscriptions to read data.
  2. Reducers must be deterministic — no filesystem, network, timers, or random. All state must come from tables.
  3. Read data via tables/subscriptions — not reducer return values. Clients get data through subscribed queries.
  4. Auto-increment IDs are not sequential — gaps are normal, do not use for ordering. Use timestamps or explicit sequence columns.
  5. ctx.sender
    is the authenticated principal
    — never trust identity passed as arguments. Always use
    ctx.sender
    for authorization.

以下五条规则可避免最常见的SpacetimeDB使用错误:
  1. Reducer是事务性的——它们不会向调用者返回数据。请使用订阅(subscriptions)来读取数据。
  2. Reducer必须是确定性的——不能访问文件系统、网络、定时器,也不能生成随机数。所有状态必须来自数据表。
  3. 通过数据表/订阅读取数据——不要依赖Reducer的返回值。客户端通过已订阅的查询获取数据。
  4. 自增ID并非连续的——出现间隙是正常现象,请勿将其用于排序。请使用时间戳或显式的序列列。
  5. ctx.sender
    是已认证的主体
    ——永远不要信任作为参数传递的身份信息。请始终使用
    ctx.sender
    进行授权验证。

Feature Implementation Checklist

功能实现检查清单

When implementing a feature that spans backend and client:
  1. Backend: Define table(s) to store the data
  2. Backend: Define reducer(s) to mutate the data
  3. Client: Subscribe to the table(s)
  4. Client: Call the reducer(s) from UI — do not skip this step
  5. Client: Render the data from the table(s)
Common mistake: Building backend tables/reducers but forgetting to wire up the client to call them.

当实现跨后端与客户端的功能时:
  1. 后端:定义用于存储数据的数据表
  2. 后端:定义用于修改数据的Reducer
  3. 客户端:订阅对应的数据表
  4. 客户端:从UI调用Reducer——请勿跳过此步骤
  5. 客户端:渲染来自数据表的数据
常见错误:构建了后端数据表/Reducer,但忘记在客户端中调用它们。

Debugging Checklist

调试检查清单

When things are not working:
  1. Is SpacetimeDB server running? (
    spacetime start
    )
  2. Is the module published? (
    spacetime publish
    )
  3. Are client bindings generated? (
    spacetime generate
    )
  4. Check server logs for errors (
    spacetime logs <db-name>
    )
  5. Is the reducer actually being called from the client?

当功能无法正常工作时:
  1. SpacetimeDB服务器是否在运行?(执行
    spacetime start
  2. 模块是否已发布?(执行
    spacetime publish
  3. 是否生成了客户端绑定?(执行
    spacetime generate
  4. 检查服务器日志中的错误(执行
    spacetime logs <db-name>
  5. 客户端是否实际调用了Reducer?

CLI Commands

CLI命令

bash
undefined
bash
undefined

Start local SpacetimeDB

启动本地SpacetimeDB

spacetime start
spacetime start

Publish module

发布模块

spacetime publish <db-name> --project-path <module-path>
spacetime publish <db-name> --project-path <module-path>

Clear and republish

清空并重新发布

spacetime publish <db-name> --clear-database -y --project-path <module-path>
spacetime publish <db-name> --clear-database -y --project-path <module-path>

Generate client bindings

生成客户端绑定

spacetime generate --lang <lang> --out-dir <out> --project-path <module-path>
spacetime generate --lang <lang> --out-dir <out> --project-path <module-path>

View logs

查看日志

spacetime logs <db-name>

---
spacetime logs <db-name>

---

What SpacetimeDB Is

SpacetimeDB是什么

SpacetimeDB combines a database and application server into a single deployable unit. Clients connect directly to the database and execute application logic inside it. The system is optimized for real-time applications requiring maximum speed and minimum latency.
Key characteristics:
  • In-memory execution: All application state lives in memory for sub-millisecond access
  • Persistent storage: Data is automatically persisted to a write-ahead log (WAL) for durability
  • Real-time synchronization: Changes are automatically pushed to subscribed clients
  • Single deployment: No separate servers, containers, or infrastructure to manage
SpacetimeDB powers BitCraft Online, an MMORPG where the entire game backend (chat, items, resources, terrain, player positions) runs as a single SpacetimeDB module.
SpacetimeDB将数据库与应用服务器整合为一个可部署的独立单元。客户端直接连接到数据库,并在其中执行应用逻辑。该系统针对需要极致速度与最低延迟的实时应用进行了优化。
核心特性:
  • 内存内执行:所有应用状态都存储在内存中,实现亚毫秒级访问
  • 持久化存储:数据会自动持久化到预写日志(WAL)中,确保数据耐用性
  • 实时同步:数据变化会自动推送给已订阅的客户端
  • 单一部署单元:无需管理单独的服务器、容器或基础设施
SpacetimeDB为MMORPG游戏BitCraft Online提供支持,该游戏的整个后端(聊天、物品、资源、地形、玩家位置)都作为单个SpacetimeDB模块运行。

The Five Zen Principles

五大核心原则

SpacetimeDB is built on five core principles that guide both development and usage:
  1. Everything is a Table: Your entire application state lives in tables. No separate cache layer, no Redis, no in-memory state to synchronize. The database IS your state.
  2. Everything is Persistent: SpacetimeDB persists everything by default, including full history. Persistence only increases latency, never decreases throughput. Modern SSDs can write 15+ GB/s.
  3. Everything is Real-Time: Clients are replicas of server state. Subscribe to data and it flows automatically. No polling, no fetching.
  4. Everything is Transactional: Every reducer runs atomically. Either all changes succeed or all roll back. No partial updates, no corrupted state.
  5. Everything is Programmable: Modules are real code (Rust, C#, TypeScript) running inside the database. Full Turing-complete power for any logic.
SpacetimeDB基于五大核心原则构建,指导其开发与使用:
  1. 一切皆为数据表:你的整个应用状态都存储在数据表中。无需单独的缓存层、Redis或需要同步的内存状态。数据库就是你的状态。
  2. 一切皆可持久化:SpacetimeDB默认持久化所有数据,包括完整历史记录。持久化只会增加延迟,绝不会降低吞吐量。现代SSD的写入速度可达15GB/s以上。
  3. 一切皆为实时:客户端是服务器状态的副本。订阅数据后,数据会自动同步。无需轮询或主动获取。
  4. 一切皆为事务性:每个Reducer都以原子方式运行。要么所有更改都成功,要么全部回滚。不会出现部分更新或损坏的状态。
  5. 一切皆可编程:模块是运行在数据库内部的真实代码(Rust、C#、TypeScript)。拥有图灵完备的能力,可实现任何逻辑。

Tables

数据表

Tables store all data in SpacetimeDB. They use the relational model and support SQL queries for subscriptions.
数据表存储SpacetimeDB中的所有数据。它们采用关系模型,并支持通过SQL查询进行订阅。

Defining Tables

定义数据表

Tables are defined using language-specific attributes:
Rust:
rust
#[spacetimedb::table(name = player, public)]
pub struct Player {
    #[primary_key]
    #[auto_inc]
    id: u32,
    #[index(btree)]
    name: String,
    #[unique]
    email: String,
}
C#:
csharp
[SpacetimeDB.Table(Name = "Player", Public = true)]
public partial struct Player
{
    [SpacetimeDB.PrimaryKey]
    [SpacetimeDB.AutoInc]
    public uint Id;
    [SpacetimeDB.Index.BTree]
    public string Name;
    [SpacetimeDB.Unique]
    public string Email;
}
TypeScript:
typescript
const players = table(
  { name: 'players', public: true },
  {
    id: t.u32().primaryKey().autoInc(),
    name: t.string().index('btree'),
    email: t.string().unique(),
  }
);
数据表使用特定语言的属性进行定义:
Rust:
rust
#[spacetimedb::table(name = player, public)]
pub struct Player {
    #[primary_key]
    #[auto_inc]
    id: u32,
    #[index(btree)]
    name: String,
    #[unique]
    email: String,
}
C#:
csharp
[SpacetimeDB.Table(Name = "Player", Public = true)]
public partial struct Player
{
    [SpacetimeDB.PrimaryKey]
    [SpacetimeDB.AutoInc]
    public uint Id;
    [SpacetimeDB.Index.BTree]
    public string Name;
    [SpacetimeDB.Unique]
    public string Email;
}
TypeScript:
typescript
const players = table(
  { name: 'players', public: true },
  {
    id: t.u32().primaryKey().autoInc(),
    name: t.string().index('btree'),
    email: t.string().unique(),
  }
);

Table Visibility

数据表可见性

  • Private tables (default): Only accessible by reducers and the database owner
  • Public tables: Exposed for client read access through subscriptions. Writes still require reducers.
  • 私有数据表(默认):仅Reducer和数据库所有者可访问
  • 公共数据表:允许客户端通过订阅进行读取访问。写入仍需通过Reducer完成。

Table Design Principles

数据表设计原则

Organize data by access pattern, not by entity:
Decomposed approach (recommended):
Player          PlayerState         PlayerStats
id         <--  player_id           player_id
name            position_x          total_kills
                position_y          total_deaths
                velocity_x          play_time
                velocity_y
Benefits:
  • Reduced bandwidth (clients subscribing to positions do not receive settings updates)
  • Cache efficiency (similar update frequencies in contiguous memory)
  • Schema evolution (add columns without affecting other tables)
  • Semantic clarity (each table has single responsibility)
根据访问模式而非实体来组织数据:
推荐的分解方式:
Player          PlayerState         PlayerStats
id         <--  player_id           player_id
name            position_x          total_kills
                position_y          total_deaths
                velocity_x          play_time
                velocity_y
优势:
  • 减少带宽消耗(订阅位置的客户端不会收到设置更新)
  • 缓存效率更高(更新频率相似的数据存储在连续内存中)
  • 架构演进更灵活(添加列不会影响其他数据表)
  • 语义更清晰(每个数据表只有单一职责)

Reducers

Reducer

Reducers are transactional functions that modify database state. They are the ONLY way to mutate tables in SpacetimeDB.
Reducer是用于修改数据库状态的事务性函数。它们是SpacetimeDB中唯一可以修改数据表的方式。

Key Properties

核心属性

  • Transactional: Run in isolated database transactions
  • Atomic: Either all changes succeed or all roll back
  • Isolated: Cannot interact with the outside world (no network, no filesystem)
  • Callable: Clients invoke reducers as remote procedure calls
  • 事务性:在隔离的数据库事务中运行
  • 原子性:要么所有更改都成功,要么全部回滚
  • 隔离性:无法与外部世界交互(无网络请求、无文件系统访问)
  • 可调用:客户端可将Reducer作为远程过程调用(RPC)来调用

Critical Reducer Rules

Reducer重要规则

  1. No global state: Relying on static variables is undefined behavior
  2. No side effects: Reducers cannot make network requests or access files
  3. Store state in tables: All persistent state must be in tables
  4. No return data: Reducers do not return data to callers — use subscriptions
  5. Must be deterministic: No random, no timers, no external I/O
  1. 无全局状态:依赖静态变量会导致未定义行为
  2. 无副作用:Reducer不能发起网络请求或访问文件
  3. 状态存储在数据表中:所有持久化状态必须存储在数据表中
  4. 不返回数据:Reducer不会向调用者返回数据——请使用订阅
  5. 必须是确定性的:不能生成随机数、不能使用定时器、不能进行外部I/O

Defining Reducers

定义Reducer

Rust:
rust
#[spacetimedb::reducer]
pub fn create_user(ctx: &ReducerContext, name: String, email: String) -> Result<(), String> {
    if name.is_empty() {
        return Err("Name cannot be empty".to_string());
    }
    ctx.db.user().insert(User { id: 0, name, email });
    Ok(())
}
C#:
csharp
[SpacetimeDB.Reducer]
public static void CreateUser(ReducerContext ctx, string name, string email)
{
    if (string.IsNullOrEmpty(name))
        throw new ArgumentException("Name cannot be empty");
    ctx.Db.User.Insert(new User { Id = 0, Name = name, Email = email });
}
Rust:
rust
#[spacetimedb::reducer]
pub fn create_user(ctx: &ReducerContext, name: String, email: String) -> Result<(), String> {
    if name.is_empty() {
        return Err("Name cannot be empty".to_string());
    }
    ctx.db.user().insert(User { id: 0, name, email });
    Ok(())
}
C#:
csharp
[SpacetimeDB.Reducer]
public static void CreateUser(ReducerContext ctx, string name, string email)
{
    if (string.IsNullOrEmpty(name))
        throw new ArgumentException("Name cannot be empty");
    ctx.Db.User.Insert(new User { Id = 0, Name = name, Email = email });
}

ReducerContext

ReducerContext

Every reducer receives a
ReducerContext
providing:
  • ctx.db
    : Access to all tables (read and write)
  • ctx.sender
    : The Identity of the caller (use this for authorization, never trust args)
  • ctx.connection_id
    : The connection ID of the caller
  • ctx.timestamp
    : The current timestamp
每个Reducer都会收到一个
ReducerContext
,提供以下功能:
  • ctx.db
    :访问所有数据表(读/写)
  • ctx.sender
    :调用者的身份信息(请使用此信息进行授权,永远不要信任参数)
  • ctx.connection_id
    :调用者的连接ID
  • ctx.timestamp
    :当前时间戳

Subscriptions

订阅

Subscriptions replicate database rows to clients in real-time. When you subscribe to a query, SpacetimeDB sends matching rows immediately and pushes updates whenever those rows change.
订阅功能可将数据库行实时复制到客户端。当你订阅某个查询时,SpacetimeDB会立即发送匹配的行,并在这些行发生变化时推送更新。

How Subscriptions Work

订阅工作原理

  1. Subscribe: Register SQL queries describing needed data
  2. Receive initial data: All matching rows are sent immediately
  3. Receive updates: Real-time updates when subscribed rows change
  4. React to changes: Use callbacks (
    onInsert
    ,
    onDelete
    ,
    onUpdate
    ) to handle changes
  1. 订阅:注册描述所需数据的SQL查询
  2. 接收初始数据:立即发送所有匹配的行
  3. 接收更新:当订阅的行发生变化时,实时推送更新
  4. 响应变化:使用回调函数(
    onInsert
    onDelete
    onUpdate
    )处理变化

Client-Side Usage

客户端使用示例

TypeScript:
typescript
const conn = DbConnection.builder()
  .withUri('wss://maincloud.spacetimedb.com')
  .withModuleName('my_module')
  .onConnect((ctx) => {
    ctx.subscriptionBuilder()
      .onApplied(() => console.log('Subscription ready!'))
      .subscribe(['SELECT * FROM user', 'SELECT * FROM message']);
  })
  .build();

// React to changes
conn.db.user.onInsert((ctx, user) => console.log(`New user: ${user.name}`));
conn.db.user.onDelete((ctx, user) => console.log(`User left: ${user.name}`));
conn.db.user.onUpdate((ctx, old, new_) => console.log(`${old.name} -> ${new_.name}`));
TypeScript:
typescript
const conn = DbConnection.builder()
  .withUri('wss://maincloud.spacetimedb.com')
  .withModuleName('my_module')
  .onConnect((ctx) => {
    ctx.subscriptionBuilder()
      .onApplied(() => console.log('Subscription ready!'))
      .subscribe(['SELECT * FROM user', 'SELECT * FROM message']);
  })
  .build();

// 响应变化
conn.db.user.onInsert((ctx, user) => console.log(`New user: ${user.name}`));
conn.db.user.onDelete((ctx, user) => console.log(`User left: ${user.name}`));
conn.db.user.onUpdate((ctx, old, new_) => console.log(`${old.name} -> ${new_.name}`));

Subscription Best Practices

订阅最佳实践

  1. Group subscriptions by lifetime: Keep always-needed data separate from temporary subscriptions
  2. Subscribe before unsubscribing: When updating subscriptions, subscribe to new data first
  3. Avoid overlapping queries: Distinct queries returning overlapping data cause redundant processing
  4. Use indexes: Queries on indexed columns are efficient; full table scans are expensive
  1. 按生命周期分组订阅:将始终需要的数据与临时订阅分开
  2. 先订阅再取消订阅:更新订阅时,先订阅新数据
  3. 避免重叠查询:返回重叠数据的不同查询会导致冗余处理
  4. 使用索引:针对索引列的查询效率更高;全表扫描开销很大

Modules

模块

Modules are WebAssembly bundles containing application logic that runs inside the database.
模块是包含应用逻辑的WebAssembly包,运行在数据库内部。

Module Components

模块组件

  • Tables: Define the data schema
  • Reducers: Define callable functions that modify state
  • Views: Define read-only computed queries
  • Procedures: (Beta) Functions that can have side effects (HTTP requests)
  • 数据表:定义数据架构
  • Reducer:定义可调用的状态修改函数
  • 视图:定义只读的计算查询
  • 过程(测试版):可产生副作用的函数(如HTTP请求)

Module Languages

模块支持的语言

Server-side modules can be written in:
  • Rust
  • C#
  • TypeScript (beta)
服务器端模块可使用以下语言编写:
  • Rust
  • C#
  • TypeScript(测试版)

Module Lifecycle

模块生命周期

  1. Write: Define tables and reducers in your chosen language
  2. Compile: Build to WebAssembly using the SpacetimeDB CLI
  3. Publish: Upload to a SpacetimeDB host with
    spacetime publish
  4. Hot-swap: Republish to update code without disconnecting clients
  1. 编写:使用你选择的语言定义数据表和Reducer
  2. 编译:使用SpacetimeDB CLI构建为WebAssembly
  3. 发布:使用
    spacetime publish
    上传至SpacetimeDB主机
  4. 热替换:重新发布以更新代码,无需断开客户端连接

Identity

身份认证

Identity is SpacetimeDB's authentication system based on OpenID Connect (OIDC).
身份认证是SpacetimeDB基于OpenID Connect(OIDC)的认证系统。

Identity Concepts

身份认证概念

  • Identity: A long-lived, globally unique identifier for a user. Derived from OIDC issuer and subject claims.
  • ConnectionId: Identifies a specific client connection. A user may have multiple connections.
  • Identity:用户的长期全局唯一标识符。由OIDC发行方和主体声明派生而来。
  • ConnectionId:标识特定的客户端连接。一个用户可以拥有多个连接。

Identity in Reducers

Reducer中的身份认证

rust
#[spacetimedb::reducer]
pub fn do_something(ctx: &ReducerContext) {
    let caller_identity = ctx.sender;  // Who is calling this reducer?
    // Use identity for authorization checks
    // NEVER trust identity passed as a reducer argument
}
rust
#[spacetimedb::reducer]
pub fn do_something(ctx: &ReducerContext) {
    let caller_identity = ctx.sender;  // 谁在调用这个Reducer?
    // 使用身份信息进行授权检查
    // 永远不要信任作为Reducer参数传递的身份信息
}

Authentication Providers

认证提供商

SpacetimeDB works with any OIDC provider:
  • SpacetimeAuth: Built-in managed provider (simple, production-ready)
  • Third-party: Auth0, Clerk, Keycloak, Google, GitHub, etc.
SpacetimeDB可与任何OIDC提供商配合使用:
  • SpacetimeAuth:内置的托管提供商(简单、可用于生产环境)
  • 第三方提供商:Auth0、Clerk、Keycloak、Google、GitHub等

SATS (SpacetimeDB Algebraic Type System)

SATS(SpacetimeDB代数类型系统)

SATS is the type system and serialization format used throughout SpacetimeDB.
SATS是SpacetimeDB使用的类型系统和序列化格式。

Core Types

核心类型

CategoryTypes
Primitives
Bool
,
U8
-
U256
,
I8
-
I256
,
F32
,
F64
,
String
Composite
ProductType
(structs),
SumType
(enums/tagged unions)
Collections
Array
,
Map
Special
Identity
,
ConnectionId
,
ScheduleAt
类别类型
基本类型
Bool
,
U8
-
U256
,
I8
-
I256
,
F32
,
F64
,
String
复合类型
ProductType
(结构体),
SumType
(枚举/标记联合)
集合类型
Array
,
Map
特殊类型
Identity
,
ConnectionId
,
ScheduleAt

Serialization Formats

序列化格式

  • BSATN: Binary format for module-host communication and row storage
  • SATS-JSON: JSON format for HTTP API and WebSocket text protocol
  • BSATN:用于模块与主机通信以及行存储的二进制格式
  • SATS-JSON:用于HTTP API和WebSocket文本协议的JSON格式

Type Compatibility

类型兼容性

Types must implement
SpacetimeType
to be used in tables and reducers. This is automatic for primitive types and structs using the appropriate attributes.
类型必须实现
SpacetimeType
才能在数据表和Reducer中使用。对于基本类型和使用适当属性定义的结构体,这是自动完成的。

Client-Server Data Flow

客户端-服务器数据流

Write Path (Client to Database)

写入路径(客户端到数据库)

  1. Client calls reducer (e.g.,
    ctx.reducers.createUser("Alice")
    )
  2. Request sent over WebSocket to SpacetimeDB host
  3. Host validates identity and executes reducer in transaction
  4. On success, changes are committed; on error, all changes roll back
  5. Subscribed clients receive updates for affected rows
  1. 客户端调用Reducer(例如
    ctx.reducers.createUser("Alice")
  2. 请求通过WebSocket发送至SpacetimeDB主机
  3. 主机验证身份并在事务中执行Reducer
  4. 成功则提交更改;失败则所有更改回滚
  5. 已订阅的客户端收到受影响行的更新

Read Path (Database to Client)

读取路径(数据库到客户端)

  1. Client subscribes with SQL queries (e.g.,
    SELECT * FROM user
    )
  2. Server evaluates query and sends matching rows
  3. Client maintains local cache of subscribed data
  4. When subscribed data changes, server pushes delta updates
  5. Client cache is automatically updated; callbacks fire
  1. 客户端使用SQL查询进行订阅(例如
    SELECT * FROM user
  2. 服务器执行查询并发送匹配的行
  3. 客户端维护订阅数据的本地缓存
  4. 当订阅的数据发生变化时,服务器推送增量更新
  5. 客户端缓存自动更新;触发回调函数

Data Flow Diagram

数据流图

┌─────────────────────────────────────────────────────────┐
│                        CLIENT                           │
│  ┌─────────────┐     ┌─────────────────────────────┐   │
│  │  Reducers   │────>│     Local Cache (Read)      │   │
│  │  (Write)    │     │  - Tables from subscriptions│   │
│  └─────────────┘     │  - Automatically synced     │   │
│         │            └─────────────────────────────┘   │
└─────────│──────────────────────────│───────────────────┘
          │ WebSocket                │ Updates pushed
          v                          │
┌─────────────────────────────────────────────────────────┐
│                     SpacetimeDB                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │                    Module                        │   │
│  │  - Reducers (transactional logic)               │   │
│  │  - Tables (in-memory + persisted)               │   │
│  │  - Subscriptions (real-time queries)            │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────┐
│                        CLIENT                           │
│  ┌─────────────┐     ┌─────────────────────────────┐   │
│  │  Reducers   │────>│     Local Cache (Read)      │   │
│  │  (Write)    │     │  - Tables from subscriptions│   │
│  └─────────────┘     │  - Automatically synced     │   │
│         │            └─────────────────────────────┘   │
└─────────│──────────────────────────│───────────────────┘
          │ WebSocket                │ Updates pushed
          v                          │
┌─────────────────────────────────────────────────────────┐
│                     SpacetimeDB                         │
│  ┌─────────────────────────────────────────────────┐   │
│  │                    Module                        │   │
│  │  - Reducers (transactional logic)               │   │
│  │  - Tables (in-memory + persisted)               │   │
│  │  - Subscriptions (real-time queries)            │   │
│  └─────────────────────────────────────────────────┘   │
└─────────────────────────────────────────────────────────┘

When to Use SpacetimeDB

何时使用SpacetimeDB

Ideal Use Cases

理想使用场景

  • Real-time games: MMOs, multiplayer games, turn-based games
  • Collaborative applications: Document editing, whiteboards, design tools
  • Chat and messaging: Real-time communication with presence
  • Live dashboards: Streaming analytics and monitoring
  • IoT applications: Sensor data with real-time updates
  • 实时游戏:MMORPG、多人游戏、回合制游戏
  • 协作应用:文档编辑、白板、设计工具
  • 聊天与消息:带在线状态的实时通信
  • 实时仪表盘:流式分析与监控
  • IoT应用:带实时更新的传感器数据

Key Decision Factors

关键决策因素

Choose SpacetimeDB when you need:
  • Sub-10ms latency for reads and writes
  • Automatic real-time synchronization
  • Transactional guarantees for all operations
  • Simplified architecture (no separate cache, queue, or server)
当你需要以下特性时,选择SpacetimeDB:
  • 读写延迟低于10毫秒
  • 自动实时同步
  • 所有操作的事务保证
  • 简化的架构(无需单独的缓存、队列或服务器)

Less Suitable For

不太适合的场景

  • Batch analytics: SpacetimeDB is optimized for OLTP, not OLAP
  • Large blob storage: Better suited for structured relational data
  • Stateless APIs: Traditional REST APIs do not need real-time sync
  • 批量分析:SpacetimeDB针对OLTP优化,而非OLAP
  • 大对象存储:更适合结构化关系数据
  • 无状态API:传统REST API不需要实时同步

Comparison to Traditional Architectures

与传统架构的对比

Traditional Stack

传统技术栈

Client
   v
Load Balancer
   v
Web/Game Servers (stateless or stateful)
   ├──> Cache (Redis)
   v
Database (PostgreSQL, MySQL)
   v
Message Queue (for real-time)
Pain points:
  • Multiple systems to deploy and manage
  • Cache invalidation complexity
  • State synchronization between servers
  • Manual real-time implementation
  • Horizontal scaling complexity
Client
   v
Load Balancer
   v
Web/Game Servers (stateless or stateful)
   ├──> Cache (Redis)
   v
Database (PostgreSQL, MySQL)
   v
Message Queue (for real-time)
痛点:
  • 需要部署和管理多个系统
  • 缓存失效的复杂性
  • 服务器间的状态同步
  • 手动实现实时功能
  • 水平扩展的复杂性

SpacetimeDB Stack

SpacetimeDB技术栈

Client
   v
SpacetimeDB Host
   v
Module (your logic + tables)
Benefits:
  • Single deployment target
  • No cache layer needed (in-memory by design)
  • Automatic real-time synchronization
  • Built-in horizontal scaling (future)
  • Transactional guarantees everywhere
Client
   v
SpacetimeDB Host
   v
Module (your logic + tables)
优势:
  • 单一部署目标
  • 无需缓存层(设计上就是内存内存储)
  • 自动实时同步
  • 内置水平扩展(未来支持)
  • 所有操作都有事务保证

Smart Contract Comparison

与智能合约的对比

SpacetimeDB modules are conceptually similar to smart contracts:
  • Application logic runs inside the data layer
  • Transactions are atomic and verified
  • State changes are deterministic
Key differences:
  • SpacetimeDB is orders of magnitude faster (no consensus overhead)
  • Full relational database capabilities
  • No blockchain or cryptocurrency involved
  • Designed for real-time, not eventual consistency
SpacetimeDB模块在概念上与智能合约类似:
  • 应用逻辑运行在数据层内部
  • 事务是原子的且经过验证
  • 状态变化是确定性的
核心区别:
  • SpacetimeDB速度快几个数量级(无需共识开销)
  • 具备完整的关系数据库功能
  • 不涉及区块链或加密货币
  • 专为实时设计,而非最终一致性

Common Patterns

常见模式

Authentication check in reducer:
rust
#[spacetimedb::reducer]
fn admin_action(ctx: &ReducerContext) -> Result<(), String> {
    let admin = ctx.db.admin().identity().find(&ctx.sender)
        .ok_or("Not an admin")?;
    // ... perform admin action
    Ok(())
}
Moving between tables (state machine):
rust
#[spacetimedb::reducer]
fn login(ctx: &ReducerContext) -> Result<(), String> {
    let player = ctx.db.logged_out_player().identity().find(&ctx.sender)
        .ok_or("Not found")?;
    ctx.db.player().insert(player.clone());
    ctx.db.logged_out_player().identity().delete(&ctx.sender);
    Ok(())
}
Scheduled reducer:
rust
#[spacetimedb::table(name = reminder, scheduled(send_reminder))]
pub struct Reminder {
    #[primary_key]
    #[auto_inc]
    id: u64,
    scheduled_at: ScheduleAt,
    message: String,
}

#[spacetimedb::reducer]
fn send_reminder(ctx: &ReducerContext, reminder: Reminder) {
    // This runs at the scheduled time
    log::info!("Reminder: {}", reminder.message);
}

Reducer中的认证检查:
rust
#[spacetimedb::reducer]
fn admin_action(ctx: &ReducerContext) -> Result<(), String> {
    let admin = ctx.db.admin().identity().find(&ctx.sender)
        .ok_or("Not an admin")?;
    // ... 执行管理员操作
    Ok(())
}
数据表间的状态转移(状态机):
rust
#[spacetimedb::reducer]
fn login(ctx: &ReducerContext) -> Result<(), String> {
    let player = ctx.db.logged_out_player().identity().find(&ctx.sender)
        .ok_or("Not found")?;
    ctx.db.player().insert(player.clone());
    ctx.db.logged_out_player().identity().delete(&ctx.sender);
    Ok(())
}
定时执行的Reducer:
rust
#[spacetimedb::table(name = reminder, scheduled(send_reminder))]
pub struct Reminder {
    #[primary_key]
    #[auto_inc]
    id: u64,
    scheduled_at: ScheduleAt,
    message: String,
}

#[spacetimedb::reducer]
fn send_reminder(ctx: &ReducerContext, reminder: Reminder) {
    // 此函数会在预定时间执行
    log::info!("Reminder: {}", reminder.message);
}

Editing Behavior

编辑规范

When modifying SpacetimeDB code:
  • Make the smallest change necessary
  • Do NOT touch unrelated files, configs, or dependencies
  • Do NOT invent new SpacetimeDB APIs — use only what exists in docs or this repo
修改SpacetimeDB代码时:
  • 只做必要的最小改动
  • 不要修改无关文件、配置或依赖
  • 不要发明新的SpacetimeDB API——仅使用文档或此仓库中已有的API