spacetimedb-unity

Integrate SpacetimeDB with Unity game projects. Use when building Unity clients with MonoBehaviour lifecycle, FrameTick, and PlayerPrefs token persistence.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "spacetimedb-unity" with this command: npx skills add clockworklabs/spacetimedb/clockworklabs-spacetimedb-spacetimedb-unity

SpacetimeDB Unity Integration

This skill covers Unity-specific patterns for connecting to SpacetimeDB. For server-side module development and general C# SDK usage, see the spacetimedb-csharp skill.


HALLUCINATED APIs — DO NOT USE

// WRONG — these do not exist in Unity SDK
SpacetimeDBClient.instance.Connect(...);    // Use DbConnection.Builder()
SpacetimeDBClient.instance.Subscribe(...);  // Use conn.SubscriptionBuilder()
NetworkManager.RegisterReducer(...);        // SpacetimeDB is not a Unity networking plugin

// WRONG — old 1.0 patterns
.WithModuleName("my-db")                    // Use .WithDatabaseName() (2.0)
ScheduleAt.Time(futureTime)                 // Use new ScheduleAt.Time(futureTime)

Common Mistakes

WrongRightError
Not calling FrameTick()conn?.FrameTick() in Update()No callbacks fire
Accessing conn.Db from background threadCopy data in callback, use on main threadData races / crashes
Forgetting DontDestroyOnLoadAdd to manager Awake()Connection lost on scene load
Connecting in Update()Connect in Start() or on user actionReconnects every frame
Not saving auth tokenPlayerPrefs.SetString(...) in OnConnectNew identity every session
Missing generated bindingsRun spacetime generate --lang csharpCompile errors

Installation

Add via Unity Package Manager using the git URL:

https://github.com/clockworklabs/com.clockworklabs.spacetimedbsdk.git

Window > Package Manager > + > Add package from git URL


Generate Module Bindings

spacetime generate --lang csharp --out-dir Assets/SpacetimeDB/module_bindings --module-path PATH_TO_MODULE

Place generated files in your Assets folder so Unity compiles them.


SpacetimeManager Singleton

The core pattern for Unity integration. This MonoBehaviour manages the connection lifecycle.

using UnityEngine;
using SpacetimeDB;
using SpacetimeDB.Types;

public class SpacetimeManager : MonoBehaviour
{
    private const string TOKEN_KEY = "SpacetimeAuthToken";
    private const string SERVER_URI = "http://localhost:3000";
    private const string DATABASE_NAME = "my-game";

    public static SpacetimeManager Instance { get; private set; }
    public DbConnection Connection { get; private set; }
    public Identity LocalIdentity { get; private set; }

    void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    void Start()
    {
        string savedToken = PlayerPrefs.GetString(TOKEN_KEY, null);

        Connection = DbConnection.Builder()
            .WithUri(SERVER_URI)
            .WithDatabaseName(DATABASE_NAME)
            .WithToken(savedToken)
            .OnConnect(OnConnected)
            .OnConnectError(err => Debug.LogError($"Connection failed: {err}"))
            .OnDisconnect((conn, err) => {
                if (err != null) Debug.LogError($"Disconnected: {err}");
            })
            .Build();
    }

    void Update()
    {
        Connection?.FrameTick();
    }

    void OnDestroy()
    {
        Connection?.Disconnect();
    }

    private void OnConnected(DbConnection conn, Identity identity, string authToken)
    {
        LocalIdentity = identity;
        PlayerPrefs.SetString(TOKEN_KEY, authToken);
        PlayerPrefs.Save();

        Debug.Log($"Connected as: {identity}");

        conn.SubscriptionBuilder()
            .OnApplied(OnSubscriptionApplied)
            .SubscribeToAllTables();
    }

    private void OnSubscriptionApplied(SubscriptionEventContext ctx)
    {
        Debug.Log("Subscription applied — game state loaded");
    }
}

FrameTick — Critical

FrameTick() must be called every frame in Update(). The SDK queues all network messages and only processes them when you call FrameTick(). Without it:

  • No callbacks fire (OnInsert, OnUpdate, OnDelete, reducer callbacks)
  • The client appears frozen
void Update()
{
    Connection?.FrameTick();
}

Thread safety: FrameTick() processes messages on the calling thread (the main thread in Unity). Do NOT call it from a background thread. Do NOT access conn.Db from background threads.


Subscribing to Tables

Subscribe in the OnConnected callback:

private void OnConnected(DbConnection conn, Identity identity, string authToken)
{
    // ...save token...

    // Development: subscribe to all
    conn.SubscriptionBuilder()
        .OnApplied(OnSubscriptionApplied)
        .SubscribeToAllTables();

    // Production: subscribe to specific tables
    conn.SubscriptionBuilder()
        .OnApplied(OnSubscriptionApplied)
        .Subscribe(new[] {
            "SELECT * FROM player",
            "SELECT * FROM game_state"
        });
}

Row Callbacks for Game State

Register callbacks to update Unity GameObjects when table data changes.

void RegisterCallbacks()
{
    Connection.Db.Player.OnInsert += (EventContext ctx, Player player) => {
        SpawnPlayerObject(player);
    };

    Connection.Db.Player.OnDelete += (EventContext ctx, Player player) => {
        DestroyPlayerObject(player.Id);
    };

    Connection.Db.Player.OnUpdate += (EventContext ctx, Player oldPlayer, Player newPlayer) => {
        UpdatePlayerObject(newPlayer);
    };
}

Register these in OnSubscriptionApplied (after initial data is loaded) or in Start() before connecting.


Calling Reducers from UI

public class GameUI : MonoBehaviour
{
    public void OnMoveButtonClicked(Vector2 direction)
    {
        SpacetimeManager.Instance.Connection.Reducers.MovePlayer(direction.x, direction.y);
    }

    public void OnSendChat(string message)
    {
        SpacetimeManager.Instance.Connection.Reducers.SendMessage(message);
    }
}

Reducer Callbacks

SpacetimeManager.Instance.Connection.Reducers.OnSendMessage += (ReducerEventContext ctx, string text) => {
    if (ctx.Event.Status is Status.Committed)
        Debug.Log($"Message sent: {text}");
    else if (ctx.Event.Status is Status.Failed(var reason))
        Debug.LogError($"Send failed: {reason}");
};

Reading the Client Cache

// Find by primary key
if (Connection.Db.Player.Id.Find(playerId) is Player player)
{
    Debug.Log($"Player: {player.Name}");
}

// Iterate all
foreach (var p in Connection.Db.Player.Iter())
{
    Debug.Log(p.Name);
}

// Filter by index
foreach (var p in Connection.Db.Player.Level.Filter(5))
{
    Debug.Log($"Level 5: {p.Name}");
}

// Count
int total = Connection.Db.Player.Count;

Unity-Specific Considerations

Main Thread Only

All SpacetimeDB SDK calls (FrameTick, conn.Db access, reducer calls) must happen on the main thread. If you need to pass data to a background thread, copy it first in the callback.

Scene Loading

Use DontDestroyOnLoad(gameObject) on the SpacetimeManager to prevent the connection from being destroyed during scene transitions. Without it, the connection drops every time you load a new scene.

IL2CPP / AOT

The SpacetimeDB SDK uses code generation. If you encounter issues with IL2CPP builds:

  • Ensure generated bindings are up to date
  • Check that link.xml preserves SpacetimeDB types if you use assembly stripping

Token Persistence

Token save/load via PlayerPrefs is demonstrated in the SpacetimeManager singleton above. If the token is stale or invalid, the server issues a new identity and token in the OnConnect callback.


Commands

spacetime start
spacetime publish <module-name> --module-path <backend-dir>
spacetime publish <module-name> --clear-database -y --module-path <backend-dir>
spacetime generate --lang csharp --out-dir Assets/SpacetimeDB/module_bindings --module-path <backend-dir>
spacetime logs <module-name>

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

spacetimedb-cli

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

spacetimedb-typescript

No summary provided by upstream source.

Repository SourceNeeds Review
General

spacetimedb-concepts

No summary provided by upstream source.

Repository SourceNeeds Review