skills/spacetimedb-best-practices/SKILL.md
SpacetimeDB development best practices for TypeScript server modules and client SDK. This skill should be used when writing, reviewing, or refactoring SpacetimeDB code to ensure optimal patterns for real-time, multiplayer applications. Triggers on tasks involving SpacetimeDB modules, tables, reducers, subscriptions, or React integration.
npx skillsauth add isyn/stdb-skills spacetimedb-best-practicesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive development guide for SpacetimeDB applications, covering both TypeScript server modules and client SDK integration with React. Contains rules across 8 categories, prioritized by impact to guide automated refactoring and code generation.
Package: spacetimedb (v1.4.0+)
Reference these guidelines when:
| Priority | Category | Impact | Prefix |
|----------|----------|--------|--------|
| 1 | Module Design | CRITICAL | module- |
| 2 | Table Schema & Indexing | CRITICAL | table- |
| 3 | Reducer Patterns | HIGH | reducer- |
| 4 | Subscription Optimization | HIGH | subscription- |
| 5 | Client State Management | MEDIUM-HIGH | client- |
| 6 | React Integration | MEDIUM | react- |
| 7 | TypeScript Patterns | MEDIUM | ts- |
| 8 | Real-time Sync | LOW-MEDIUM | sync- |
import { spacetimedb, table, t, ReducerContext } from 'spacetimedb';
// Define tables with the table builder
const Player = table(
{ name: 'player', public: true },
{
identity: t.identity().primaryKey(),
name: t.string(),
score: t.u64().index(),
isOnline: t.bool().index(),
}
);
// Define reducers
spacetimedb.reducer('create_player', { name: t.string() }, (ctx: ReducerContext, { name }) => {
ctx.db.player.insert({
identity: ctx.sender,
name,
score: 0n,
isOnline: true,
});
});
// Lifecycle hooks
spacetimedb.init((ctx: ReducerContext) => { /* module init */ });
spacetimedb.clientConnected((ctx: ReducerContext) => { /* client connected */ });
spacetimedb.clientDisconnected((ctx: ReducerContext) => { /* client disconnected */ });
import { DbConnection } from './generated';
// Build connection
const conn = DbConnection.builder()
.withUri('ws://localhost:3000')
.withModuleName('my-module')
.onConnect((ctx, identity, token) => {
// Setup subscriptions
conn.subscription(['SELECT * FROM player WHERE isOnline = true']);
})
.onDisconnect((ctx, error) => { /* handle disconnect */ })
.build();
// Call reducers
await conn.reducers.createPlayer('Alice');
// Access tables
const player = conn.db.player.identity.find(identity);
import { useTable, where, eq } from 'spacetimedb/react';
import { DbConnection, Player } from './generated';
function OnlinePlayers() {
const { rows: players } = useTable<DbConnection, Player>(
'player',
where(eq('isOnline', true))
);
return players.map(p => <div key={p.identity.toHexString()}>{p.name}</div>);
}
module-single-responsibility - One module per domain conceptmodule-lifecycle - Use lifecycle hooks appropriately (init, clientConnected, clientDisconnected)module-error-handling - Handle errors gracefully in module codemodule-type-exports - Export types for client consumptiontable-primary-keys - Choose appropriate primary key strategiestable-indexing - Add .index() for frequently queried columnstable-relationships - Model relationships between tables correctlytable-column-types - Use appropriate SpacetimeDB typesreducer-atomicity - Keep reducers atomic and focusedreducer-validation - Validate inputs at reducer entryreducer-authorization - Check caller identity for sensitive operationsreducer-batch-operations - Batch related mutations in single reducersubscription-selective - Subscribe only to needed datasubscription-filters - Use subscription filters to reduce data transfersubscription-cleanup - Clean up subscriptions when no longer neededsubscription-batching - Batch subscription setup on client connectclient-connection-lifecycle - Handle connection/reconnection properlyclient-optimistic-updates - Use optimistic updates for responsive UIclient-error-recovery - Handle reducer errors gracefullyclient-identity - Manage identity tokens securelyreact-use-subscription - Use subscription hooks correctlyreact-table-hooks - Use useTable<DbConnection, Type>() for reactive datareact-reducer-hooks - Call conn.reducers.* with proper error handlingreact-connection-status - Display connection status to usersts-generated-types - Use generated types from SpacetimeDB CLIts-strict-mode - Enable strict TypeScript for better type safetyts-discriminated-unions - Use discriminated unions for statets-type-guards - Implement type guards for runtime validationsync-conflict-resolution - Handle concurrent modificationssync-offline-support - Design for offline-first when neededsync-debounce-updates - Debounce rapid UI updatessync-presence - Implement user presence efficientlyRead individual rule files for detailed explanations and code examples:
rules/module-single-responsibility.md
rules/table-primary-keys.md
rules/_sections.md
Each rule file contains:
For the complete guide with all rules expanded: AGENTS.md
development
Review UI code for Web Interface Guidelines compliance. Use when asked to "review my UI", "check accessibility", "audit design", "review UX", or "check my site against best practices".
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------
tools
# Lobster Lobster executes multi-step workflows with approval checkpoints. Use it when: - User wants a repeatable automation (triage, monitor, sync) - Actions need human approval before executing (send, post, delete) - Multiple tool calls should run as one deterministic operation ## When to use Lobster | User intent | Use Lobster? | | ------------------------------------------------------ | --------------------------