Skip to content
Backend
Skill

/cpp-server

SpacetimeDB C++ server module SDK reference. Use when writing tables, reducers, or module logic in C++.

From plugin
spacetimedb
26k11 skills1 MCP

Claude Code

$ npx -y skills add clockworklabs/spacetimedb --skill cpp-server --agent claude-code

SKILL.md

cpp-server.SKILL.md
name: cpp-server
description: SpacetimeDB C++ server module SDK reference. Use when writing tables, reducers, or module logic in C++.
license: Apache-2.0
metadata:
  author: clockworklabs
  version: "2.0"
  role: server
  language: cpp
  cursor_globs: "**/*.cpp,**/*.h,**/*.hpp"
  cursor_always_apply: true

SpacetimeDB C++ SDK Reference

Imports

#include <spacetimedb.h>
using namespace SpacetimeDB;

Tables

Register structs with macros, then declare as tables:

struct Entity {
    uint64_t id;
    Identity owner;
    std::string name;
    bool active;
};
SPACETIMEDB_STRUCT(Entity, id, owner, name, active)
SPACETIMEDB_TABLE(Entity, entity, Public)
FIELD_PrimaryKeyAutoInc(entity, id)
FIELD_Index(entity, name)

Options:

  • `SPACETIMEDB_TABLE(Type, accessor, Public|Private)`: regular table
  • `SPACETIMEDB_TABLE(Type, accessor, Public|Private, true)`: event table

Field constraints:

  • `FIELD_PrimaryKey(accessor, field)`: primary key
  • `FIELD_PrimaryKeyAutoInc(accessor, field)`: primary key with auto-increment (use 0 on insert)
  • `FIELD_Unique(accessor, field)`: unique constraint
  • `FIELD_Index(accessor, field)`: btree index (enables `.filter()`)

Column Types

| C++ type | Notes | |----------|-------| | `uint8_t` / `uint16_t` / `uint32_t` / `uint64_t` | unsigned integers | | `SpacetimeDB::u128` / `SpacetimeDB::u256` | large unsigned integers | | `int8_t` / `int16_t` / `int32_t` / `int64_t` | signed integers | | `SpacetimeDB::i128` / `SpacetimeDB::i256` | large signed integers | | `float` / `double` | floats | | `bool` | boolean | | `std::string` | text | | `std::vector<T>` | list/array | | `std::optional<T>` | nullable column | | `Identity` | user identity | | `ConnectionId` | connection handle | | `Timestamp` | server timestamp (microseconds since epoch) | | `TimeDuration` | duration in microseconds | | `ScheduleAt` | for scheduled tables |

Indexes

// Single-column:
FIELD_Index(entity, name)
// Access: ctx.db[entity_name].filter("Alice")

// Multi-column:
FIELD_NamedMultiColumnIndex(score, by_player_and_level, player_id, level)

Range queries (included by `spacetimedb.h`; include `<spacetimedb/range_queries.h>` directly only when not using the umbrella header):

ctx.db[user_age].filter(range_inclusive(uint8_t(18), uint8_t(65)));
ctx.db[user_age].filter(range_from(uint8_t(18)));

Reducers

All reducers return `ReducerResult`. Use `Ok()` or `Err(message)`:

SPACETIMEDB_REDUCER(create_entity, ReducerContext ctx, std::string name) {
    if (name.empty()) {
        return Err("Name cannot be empty");
    }
    ctx.db[entity].insert(Entity{0, ctx.sender(), name, true});
    return Ok();
}

DB Operations

ctx.db[entity].insert(Entity{0, owner, "Sample", true});     // Insert (0 for autoInc)
ctx.db[entity_id].find(entityId);                             // Find by PK → std::optional
ctx.db[entity_identity].find(ctx.sender());                   // Find by unique column
ctx.db[entity_name].filter("Alice");                          // Filter by index → iterable
ctx.db[entity];                                               // All rows → iterable (range-for)
ctx.db[entity].count();                                       // Count rows

// Update: find, mutate, update
if (auto e = ctx.db[entity_id].find(entityId)) {
    e->name = "New Name";
    ctx.db[entity_id].update(*e);
}

// Delete by primary key
ctx.db[entity_id].delete_by_key(entityId);

Note: Bracket notation `ctx.db[accessor]` is used for all table access. The accessor name comes from `SPACETIMEDB_TABLE` and `FIELD_*` macros.

Lifecycle Hooks

SPACETIMEDB_INIT(init, ReducerContext ctx) {
    LOG_INFO("Database initializing...");
    return Ok();
}

SPACETIMEDB_CLIENT_CONNECTED(on_connect, ReducerContext ctx) {
    LOG_INFO("Connected: " + ctx.sender().to_string());
    return Ok();
}

SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) {
    LOG_INFO("Disconnected: " + ctx.sender().to_string());
    return Ok();
}

Authentication & Timestamps

// Auth: ctx.sender() is the caller's Identity
if (row.owner != ctx.sender()) {
    return Err("unauthorized");
}

// Server timestamps
ctx.db[item].insert(Item{0, ctx.sender(), ctx.timestamp});

// Timestamp arithmetic
Timestamp later = ctx.timestamp + TimeDuration::from_seconds(10);

Reducer Context

`ReducerContext` is the single source of sender identity, deterministic time, and deterministic randomness inside a reducer. Always go through `ctx` for these. Standard library clocks and random sources are not available in modules.

ctx.db[table]          // Table access (bracket notation)
ctx.sender()           // Caller's Identity
ctx.timestamp          // Invocation timestamp
ctx.connection_id      // std::optional<ConnectionId>
ctx.identity()         // Module's own identity
ctx.rng()              // Deterministic RNG
ctx.sender_auth()      // AuthCtx with JWT claims

Environment Variables

Declare the environment in a dedicated `environment.h`:

#pragma once
#include <spacetimedb/environment_declaration.h>

SPACETIMEDB_ENV(
    (API_KEY, std::string),
    (MODE, std::string, ("development", "production")),
    (LOG_LEVEL, std::optional<std::string>)
)
// In a root entry point: ctx.env.API_KEY(), ctx.env.LOG_LEVEL()
// String-key lookup: ctx.env.get("LOG_LEVEL")

Set `SPACETIMEDB_ENV_HEADER` to this header's full path in CMake **before** adding the SpacetimeDB module library directory, so the library and module see the same context declaration. Including it manually in only one source file is insufficient. `std::string` is required; `std::optional<std::string>` permits absence. The optional third tuple element restricts allowed strings.

See the concepts skill for shared environment and secret-handling rules.

Scheduled Tables

struct Reminder {
    uint64_t scheduled_id;
    ScheduleAt scheduled_at;
    std::string message;
};
SPACETI
Read more
@clockworklabs
Ships withspacetimedb

Development at the speed of light

26k11 skills1 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
25.5k
Star history of clockworklabs/spacetimedb on GitHub, a chart by star-history.com

Other skills on spacetimedb.

cli

cli

SpacetimeDB CLI reference for initializing projects, building modules, publishing databases, querying data, and managing servers

concepts

concepts

Understand SpacetimeDB architecture and core concepts. Use when learning SpacetimeDB or making architectural decisions.

csharp-client

csharp-client

SpacetimeDB C#/.NET client SDK reference. Use when building C# clients that connect to SpacetimeDB (console, desktop, or any .NET…

mcp

mcp

Operate a running SpacetimeDB database through MCP tools rather than the CLI - list databases, read schemas, run SQL, and call…

More skills from other plugins.

backend

backend

Use this skill when contributing to InsForge's backend package. This is for maintainers editing backend routes, services,…

@insforge@insforgeInstall Skill
exa-agent

exa-agent

Use Exa Agent for multi-step web research, list-building, enrichment, structured output, run continuation, and coverage…

exa10d5.2k
@exa-labs@exa-labsInstall Skill
fde-ontology

fde-ontology

多源输入→本体检出→AI审核→场景升级→代码生成 自动化管线

dgiot4w4.9k
@dgiot@dgiotInstall Skill

Questions about cpp-server.

Which coding agents can use cpp-server?
cpp-server installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.