cli
SpacetimeDB CLI reference for initializing projects, building modules, publishing databases, querying data, and managing servers
SpacetimeDB TypeScript server module SDK reference. Use when writing tables, reducers, or module logic in TypeScript.
$ npx -y skills add clockworklabs/spacetimedb --skill typescript-server --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/typescript-serverContext preview
The summary Claude sees to decide when to auto-load this skill.
SpacetimeDB TypeScript server module SDK reference. Use when writing tables, reducers, or module logic in TypeScript.
name: typescript-server description: SpacetimeDB TypeScript server module SDK reference. Use when writing tables, reducers, or module logic in TypeScript. license: Apache-2.0 metadata: author: clockworklabs version: "2.0" role: server language: typescript cursor_globs: "**/*.ts" cursor_always_apply: true
Tables are built with `table()`, bound with `schema()`, and exported as default. Reducers and lifecycle hooks are `export const`:
import { schema, table, t } from 'spacetimedb/server';
const scoreRecord = table(
{ name: 'score_record', public: true },
{
id: t.u64().primaryKey().autoInc(),
owner: t.identity(),
value: t.u32(),
}
);
const spacetimedb = schema({ scoreRecord }); // ONE object, not spread args
export default spacetimedb;
export const addRecord = spacetimedb.reducer(
{ value: t.u32() },
(ctx, { value }) => {
ctx.db.scoreRecord.insert({ id: 0n, owner: ctx.sender, value });
}
);Only table definitions belong in `schema({...})`. Row and object builders used as reducer arguments or view return types are not schema entries.
Named runtime exports are reserved for values registered with SpacetimeDB, such as reducers, lifecycle hooks, views, procedures, HTTP exports, and visibility filters. Keep ordinary helper functions and constants unexported.
Schema builders and module exports come from `spacetimedb/server`. Runtime value classes such as `ScheduleAt`, `Timestamp`, and `ConnectionId` come from the root `spacetimedb` package; `Range` comes from `spacetimedb/server`:
import {
schema, table, t, SenderError,
type InferSchema, type ReducerCtx,
} from 'spacetimedb/server';
import { ConnectionId, ScheduleAt, Timestamp } from 'spacetimedb';
import { Range } from 'spacetimedb/server';`table(OPTIONS, COLUMNS)` takes two arguments. The `name` field MUST be snake_case:
const entity = table(
{ name: 'entity', public: true },
{
identity: t.identity().primaryKey(),
name: t.string(),
active: t.bool(),
}
);Options: `name` (snake_case, recommended), `public: true`, `event: true`, `indexes: [...]`
`ctx.db` accessors are the keys passed to `schema({...})`, verbatim: `schema({ scoreRecord })` -> `ctx.db.scoreRecord`. Keep TypeScript identifiers and accessors camelCase. Use explicit `name: 'snake_case'` strings when you need a canonical database name that differs from the TypeScript identifier.
Every column is a `t` builder value:
| Builder | JS type | Notes | |---------|---------|-------| | `t.u8()` / `t.u16()` / `t.u32()` | number | | | `t.i8()` / `t.i16()` / `t.i32()` | number | | | `t.u64()` | bigint | Use `0n` literals | | `t.i64()` | bigint | Use `0n` literals | | `t.u128()` / `t.i128()` / `t.u256()` / `t.i256()` | bigint | | | `t.f64()` / `t.f32()` | number | | | `t.bool()` | boolean | | | `t.string()` | string | | | `t.identity()` | Identity | | | `t.connectionId()` | ConnectionId | | | `t.timestamp()` | Timestamp | | | `t.timeDuration()` | TimeDuration | | | `t.scheduleAt()` | ScheduleAt | |
Modifiers: `.primaryKey()`, `.autoInc()`, `.unique()`, `.index('btree')`, `.default(value)`.
Use `.default(value)` only for a newly appended migration-safe field. Do not put defaults on primary-key, unique, or auto-increment columns.
Optional columns: `nickname: t.option(t.string())`
Schema builders describe the database's wire types; they are not TypeScript type names. For example, a `t.u16()` value is a TypeScript `number`, not a value cast to a type named `u16`.
Use inline `.index('btree')` when a single-column index does not need a named accessor. Use an `indexes` entry when the accessor is named explicitly or the index spans multiple columns. Every `indexes` entry requires `columns`; do not also add `.index('btree')` to the same column.
// Inline (preferred for single-column):
authorId: t.u64().index('btree'),
// Access: ctx.db.post.authorId.filter(authorId);
// Multi-column (named):
indexes: [{ accessor: 'by_group_user', algorithm: 'btree', columns: ['groupId', 'userId'] }]
// Access: ctx.db.membership.by_group_user.filter([groupId, userId]);Prefer a multi-column index over filtering by one column and looping. Filter takes an array in index column order; a prefix scan passes the leading value bare: `filter(groupId)`.
The published module's **entry file must export the schema as default**. If you split tables (`schema.ts`) from reducers/lifecycle (`index.ts`), re-export it from the entry:
// index.ts
export { default } from './schema'; // re-export the schema for the module entryReducers are created with `spacetimedb.reducer(...)`; the export name becomes the reducer name:
export const createEntity = spacetimedb.reducer(
{ name: t.string(), age: t.i32() },
(ctx, { name, age }) => {
ctx.db.entity.insert({ identity: ctx.sender, name, age, active: true });
}
);
// No arguments, just the callback:
export const doReset = spacetimedb.reducer((ctx) => { ... });Reducer args accept any column type, including arrays of custom types: `{ splits: t.array(Split) }`. Do not pass JSON strings for structured data.
ctx.db.scoreRecord.insert({ id: 0n, owner: ctx.sender, value: 1 }); // Insert (0n for autoInc)
ctx.db.scoreRecord.id.find(recordId); // Find by PK → row | null
ctx.db.entity.identity.find(ctx.sender); // Find by unique column
[...ctx.db.post.authorId.filter(authorId)]; // Filter → spread to Array
[...ctx.db.entity.iter()]; // All rows → Array
ctx.db.scoreRecord.id.update({ ...existing, value: 2 }); // Update (spread + override)
ctx.db.scoreRecord.id.delete(recordId); // Delete by PKInsert through the table accessor (`ctx.db.
Repo: clockworklabs/spacetimedb
SpacetimeDB CLI reference for initializing projects, building modules, publishing databases, querying data, and managing servers
Understand SpacetimeDB architecture and core concepts. Use when learning SpacetimeDB or making architectural decisions.
SpacetimeDB C++ server module SDK reference. Use when writing tables, reducers, or module logic in C++.
SpacetimeDB C#/.NET client SDK reference. Use when building C# clients that connect to SpacetimeDB (console, desktop, or any .NET app).
SpacetimeDB C# server module SDK reference. Use when writing tables, reducers, or module logic in C#.
Operate a running SpacetimeDB database through MCP tools rather than the CLI - list databases, read schemas, run SQL, and call reducers. Use when the client…