cli
SpacetimeDB CLI reference for initializing projects, building modules, publishing databases, querying data, and managing servers
SpacetimeDB C#/.NET client SDK reference. Use when building C# clients that connect to SpacetimeDB (console, desktop, or any .NET app).
Claude Code
$ npx -y skills add clockworklabs/spacetimedb --skill csharp-client --agent claude-code
Codex
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a codex -y
Cursor
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a cursor -y
Gemini CLI
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a gemini-cli -y
GitHub Copilot
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a github-copilot -y
OpenCode
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a opencode -y
Windsurf
$ npx skills add clockworklabs/spacetimedb --skill csharp-client -a windsurf -y
name: csharp-client description: SpacetimeDB C#/.NET client SDK reference. Use when building C# clients that connect to SpacetimeDB (console, desktop, or any .NET app). license: Apache-2.0 metadata: author: clockworklabs version: "2.0" role: client language: csharp cursor_globs: "**/*.cs" cursor_always_apply: true
Install: `dotnet add package SpacetimeDB.ClientSDK`
Generated bindings convert snake_case names to PascalCase, including row fields: a server column `trip_id` is `TripId` on client rows.
using SpacetimeDB;
using SpacetimeDB.Types;
var conn = DbConnection.Builder()
.WithUri("http://localhost:3000")
.WithDatabaseName("my-database")
.WithToken(savedToken)
.WithCompression(Compression.Brotli) // optional; this is the default
.OnConnect((conn, identity, token) =>
{
Console.WriteLine($"Connected as: {identity}");
// Save token for reconnection
File.WriteAllText("auth_token.txt", token);
conn.SubscriptionBuilder()
.OnApplied(OnSubscriptionApplied)
.SubscribeToAllTables();
})
.OnConnectError(err => Console.Error.WriteLine($"Connection failed: {err}"))
.OnDisconnect((conn, err) =>
{
if (err != null) Console.Error.WriteLine($"Disconnected: {err}");
})
.Build();Compression options are `Compression.Brotli`, `Compression.Gzip`, and `Compression.None`. The SDK uses Brotli when `WithCompression` is omitted.
Automatic reconnect is opt-in: add `.WithAutomaticReconnect()` to the builder. Initial connection failures do not retry. After an established connection is lost, the SDK retries with exponential backoff and jitter from `MinDelay` (default 1 s) up to `MaxDelay` (default 30 s); tune them with `.WithAutomaticReconnect(new AutomaticReconnectOptions { MinDelay = ..., MaxDelay = ... })`. Values below the 500 ms and 1 s floors are raised with a warning, so that retrying clients cannot overwhelm the database. `Disconnect()` permanently stops recovery.
Keep calling `FrameTick()` while `IsActive` is false. `IsReconnecting` is true while recovering before the next handshake. Use `.OnDisconnect((conn, error, next) => ...)` and `.OnConnectError((error, next) => ...)` to inspect `NextReconnect?`: a non-null value provides `Attempt` and `Delay`; null means no retry is scheduled. Existing callback overloads still work.
`OnConnect` runs on every successful reconnect, so create the subscription in the example above only on the first connection, or move it after `Build()`. Register row callbacks once as well. The same connection, identity, table handles, and subscriptions survive; each attempt gets a fresh `ConnectionId`. Cached rows stay readable but stale during outages. The SDK replays subscriptions in one batch and emits only net row changes. Subscription `OnApplied` runs again after replay; use it to mark data ready, not for repeated one-time setup.
For expiring credentials, combine `.WithToken(initialToken)` with `.WithTokenProvider(() => RefreshTokenAsync())`, where your provider returns `Task<string>` for the same identity. The provider is not called for the initial connection. Before retries, it is called when remaining validity is at most 30 seconds or 5% of the token lifetime, whichever is greater, when expiry cannot be read, or after a reused token is rejected. Provider failures retry; rejection of a freshly provided token is terminal. No periodic refresh runs while connected. Disconnecting ignores a pending provider result but does not cancel the provider's own work.
Calls made while disconnected fail immediately. Pending reducer calls receive `Status.UnknownResult`; pending procedures and one-off queries fail with `UnknownResultException`. These calls may already have executed and are never replayed. Regenerate bindings so unhandled unknown reducer outcomes reach `OnUnhandledReducerError`.
**`FrameTick()` must be called in your main loop.** The SDK queues all network messages and only processes them when you call `FrameTick()`. Without it, no callbacks fire.
while (running)
{
conn.FrameTick();
// Your application logic...
Thread.Sleep(16); // ~60fps
}**Thread safety**: `FrameTick()` processes messages on the calling thread. Do NOT call it from a background thread. Do NOT access `conn.Db` from background threads.
// Subscribe to all tables
conn.SubscriptionBuilder()
.OnApplied(ctx => Console.WriteLine("Subscription ready"))
.SubscribeToAllTables();
// Subscribe with typed query builder (recommended)
conn.SubscriptionBuilder()
.OnApplied(OnSubscriptionApplied)
.AddQuery(q => q.From.Player().Where(p => p.Level.Gte(5u)))
.AddQuery(q => q.From.GameState())
.Subscribe();
// Or with raw SQL strings
conn.SubscriptionBuilder()
.OnApplied(OnSubscriptionApplied)
.Subscribe(new[] {
"SELECT * FROM player WHERE level >= 5",
"SELECT * FROM game_state"
});A namespace accessor `MyAuth` is nested in the generated table, reducer, and procedure APIs:
conn.SubscriptionBuilder()
.AddQuery(q => q.From.MyAuth.User())
.Subscribe();
// Rows: conn.Db.MyAuth.User
// Reducers: conn.Reducers.MyAuth.Add(10)
// Procedures: conn.Procedures.MyAuth.CountUsers((ctx, result) => { ... })The query builder and calls encode canonical names automatically. Raw SQL/HTTP/CLI calls use canonical qualified names, such as `auth_data.<table>` for a namespace explicitly named `auth_data`. All namespaces share the connection and cache.
For views with arguments (2.13+), use raw SQL; C# has no typed argument-bearing view query builder yet:
conn.SubscriptionBuilder().Subscribe(new[] { "SELECT * FROM by_id(42)" });Use explicit queries for every table on that connection, not subscribe-al
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# 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…
SpacetimeDB Rust server module SDK reference. Use when writing tables, reducers, or module logic in Rust.
Best practices for implementing JWT, API Keys, OAuth 2.1, and RBAC in a NitroStack application.