docs/docs/00200-core-concepts/00600-clients/00400-sdk-api.md
import Tabs from '@theme/Tabs'; import TabItem from '@theme/TabItem';
The SpacetimeDB client SDKs provide a comprehensive API for interacting with your database. After generating client bindings and establishing a connection, you can query data, invoke server functions, and observe real-time changes.
This page describes the core concepts and patterns that apply across all client SDKs. For language-specific details and complete API documentation, see the reference pages for Rust, C#, TypeScript, or Unreal Engine.
Before using the SDK API, you must:
spacetime generateSubscriptions replicate a subset of the database to your client, maintaining a local cache that automatically updates as the server state changes. Clients should subscribe to the data they need, then query the local cache.
Typical flow:
onApplied/OnApplied to know initial rows are presentFor lifecycle guarantees and semantics, see Subscriptions and Subscription Semantics.
import { tables } from './module_bindings';
const handle = conn
.subscriptionBuilder()
.onApplied(ctx => {
console.log(`Ready with ${ctx.db.user.count()} users`);
})
.onError((ctx, error) => {
console.error(`Subscription failed: ${error}`);
})
.subscribe([tables.user.where(r => r.online.eq(true))]);
var handle = conn
.SubscriptionBuilder()
.OnApplied(ctx =>
{
Console.WriteLine($"Ready with {ctx.Db.User.Count} users");
})
.OnError((ctx, error) =>
{
Console.WriteLine($"Subscription failed: {error}");
})
.AddQuery(q => q.From.User())
.Subscribe();
let handle = conn
.subscription_builder()
.on_applied(|ctx| {
println!("Ready with {} users", ctx.db().user().count());
})
.on_error(|_ctx, error| {
eprintln!("Subscription failed: {}", error);
})
.add_query(|q| q.from.user())
.subscribe();
TArray<FString> Queries = { TEXT("SELECT * FROM user") };
USubscriptionHandle* Handle = Conn->SubscriptionBuilder()
->OnApplied(AppliedDelegate)
->OnError(ErrorDelegate)
->Subscribe(Queries);
After a subscription is applied, reads are local and do not require network round-trips.
<Tabs groupId="client-language" queryString> <TabItem value="typescript" label="TypeScript">const userCount = conn.db.user.count();
const user = conn.db.user.name.find('Alice');
var userCount = conn.Db.User.Count;
var user = conn.Db.User.Name.Find("Alice");
let user_count = conn.db().user().count();
let user = conn.db().user().name().find("Alice");
int32 UserCount = Conn->Db->User->Count();
FUserType User = Conn->Db->User->Name->Find(TEXT("Alice"));
Use row callbacks to react when subscribed rows are inserted, updated, or deleted.
<Tabs groupId="client-language" queryString> <TabItem value="typescript" label="TypeScript">conn.db.user.onInsert((ctx, row) => {});
conn.db.user.onUpdate((ctx, oldRow, newRow) => {});
conn.db.user.onDelete((ctx, row) => {});
conn.Db.User.OnInsert += (ctx, row) => {};
conn.Db.User.OnUpdate += (ctx, oldRow, newRow) => {};
conn.Db.User.OnDelete += (ctx, row) => {};
conn.db().user().on_insert(|ctx, row| {});
conn.db().user().on_update(|ctx, old_row, new_row| {});
conn.db().user().on_delete(|ctx, row| {});
Conn->Db->User->OnInsert.AddDynamic(this, &AMyActor::OnUserInsert);
Conn->Db->User->OnUpdate.AddDynamic(this, &AMyActor::OnUserUpdate);
Conn->Db->User->OnDelete.AddDynamic(this, &AMyActor::OnUserDelete);
SubscriptionBuilder, SubscriptionHandle, query builder APISubscriptionBuilder, SubscriptionHandleSubscriptionBuilder, SubscriptionHandle