Rewrites the FAQ from 5 basic questions to a comprehensive guide
covering:
- **General** — What is SpacetimeDB, is it only for games, is it
blockchain, licensing, self-hosting
- **Comparisons** — vs Mirror/Photon/networking libs, vs
Firebase/Supabase, vs PostgreSQL
- **Architecture** — Data persistence, real-time sync, reducers vs REST,
module languages, views, procedures
- **Development** — Getting started, `spacetime dev`, SQL usage,
Unity/Unreal/React/framework support, auth
- **Deployment** — Production publishing, hot-swapping modules, schema
migrations, size limits, pricing
- **Troubleshooting** — Global database names (401/403), confusing
generate errors, resetting databases
Content drawn from README, architecture docs, Zen of SpacetimeDB, and
common user questions from GitHub issues and Discord.
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Rewrites the Maincloud deployment guide from a bare-bones stub into a
comprehensive page. Addresses all three points from #3108 plus a
community request for the connection URI.
**New content:**
1. **Finding your module on the dashboard** - Direct URL
(`spacetimedb.com/my-module`) and profile page navigation
2. **Database lifecycle** - Running vs suspended states, automatic
suspension after inactivity, automatic resumption on first request
3. **Next steps section** - Links to dashboard, SpacetimeAuth setup,
quickstart guides, and usage monitoring
**Also added:**
- Prerequisites section (CLI install + `spacetime login` to link web
account)
- Publishing workflow (initial publish, hot-swap updates,
`--delete-data`)
- Client connection code examples for TypeScript, C#, Rust, and C++ with
the Maincloud host URL (`https://maincloud.spacetimedb.com`) - per
community request in #3108
- Database deletion instructions
- Link to pricing page
Closes#3108
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Implementation of #4295
Convert existing `Name` attribute to `Accessor` to support new Canonical
Case conversation of 2.0
# API and ABI breaking changes
Yes, in C# modules, we no longer use the attribute name `Name`, it
should now be `Accessor`
# Expected complexity level and risk
1
# Testing
- [X] Build and tested locally
- [X] Ran regression tests locally
# Description of Changes
In the typescript quickstart example, this includes the server and
module name in the local storage variable name that we use for the auth
token.
This fixes an otherwise annoying issue people run into if they start
running the quickstart locally, then try to run it on maincloud. If they
have already run the app with a local server, their browser will store
the locally signed token, which will get rejected by maincloud.
# Expected complexity level and risk
1.
# Testing
I was able to connect to my local quickstart, then change the variables
to point to a module on maincloud, and I didn't get any errors.
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
## Description of Changes
This PR primarily affects the `bindings-macro` and `schema` crates to
review:
### Core changes
1. Replaces the `name` macro with `accessor` for **Tables, Views,
Procedures, and Reducers** in Rust modules.
2. Extends `RawModuleDefV10` with a new section for:
* case conversion policies
* explicit names
New sections are not validated in this PR so not functional.
3. Updates index behavior:
* Index names are now always **system-generated** for clients. Which
will be fixed in follow-up PR when we start validating RawModuleDef with
explicit names.
* The `accessor` name for an index is used only inside the module.
## Breaking changes (API/ABI)
1. **Rust modules**
* The `name` macro must be replaced with `accessor`.
2. **Client bindings (all languages)**
* Index names are now system-generated instead of using explicitly
provided names.
**Complexity:** 3
A follow-up PR will reintroduce explicit names with support for case
conversion.
---------
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <bot@clockworklabs.com>
# Description of Changes
This PR implements support for the `spacetime.json` configuration file
that can be used to set up common `generate` and `publish` targets. An
example of `spacetime.json` could look like this:
```
{
"dev_run": "pnpm dev",
"generate": [
{ "out-dir": "./foobar", "module-path": "region-module", "language": "c-sharp" },
{ "out-dir": "./global", "module-path": "global-module", "language": "c-sharp" },
],
"publish": {
"database": "bitcraft",
"module-path": "spacetimedb",
"server": "local",
"children": [
{ "database": "region-1", "module-path": "region-module", server: "local" },
{ "database": "region-2", "module-path": "region-module", server: "local" }
]
}
}
```
With this config, running `spacetime generate` without any arguments
would generate bindings for two targets: `region-module` and
`global-module`. `spacetime publish` without any arguments would publish
three modules, starting from the parent: `bitcraft`, `region-1`, and
`region-2`. On top of that, the command `pnpm dev` would be executed
when using `spacetime dev`.
It is also possible to pass additional command line arguments when
calling the `publish` and `generate` commands, but there are certain
limitations. There is a special case when passing either a module path
to generate or a module name to publish. Doing that will filter out
entries in the config file that do not match. For example, running:
```
spacetime generate --project-path global-module
```
would only generate bindings for the second entry in the `generate`
list.
In a similar fashion, running:
```
spacetime publish region-1
```
would only publish the child database with the name `region-1`
Passing other existing arguments is also possible, but not all of the
arguments are available for multiple configs. For example, when running
`spacetime publish --server maincloud`, the publish command would be
applied to all of the modules listed in the config file, but the
`server` value from the command line arguments would take precedence.
Running with arguments like `--bin-path` would, however, would throw an
error as `--bin-path` makes sense only in a context of a specific
module, thus this wouldn't work: `spacetime publish --bin-path
spacetimedb/target/debug/bitcraft.wasm`. I will throw an error unless
there is only one entry to process, thus `spacetime publish --bin-path
spacetimedb/target/debug/bitcraft.wasm bitcraft` would work, as it
filters the publish targets to one entry.
# API and ABI breaking changes
None
# Expected complexity level and risk
3
The config file in itself is not overly complex, but when coupled with
the CLI it is somewhat tricky to get right. There are also some changes
that I had to make to how clap arguments are validated - because the
values can now come from both the config file and the clap config, we
can't use some of the built-in validations like `required`, or at least
I haven't found a clean way to do so.
# Testing
I've added some automated tests, but more tests and manual testing is
coming.
---------
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: bradleyshep <148254416+bradleyshep@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: = <cloutiertyler@gmail.com>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
Fixes a problem with renaming the project from client_unreal to
blackholio which causes the C++ header code to be incorrect
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Updates a small portion of the Unreal Tutorial documentation
# Testing
Testing the current docs is what found the issue.
- [x] Rebuilt the Unreal Blackholio from the tutorial
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Implements the rest of the casing proposal.
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
# Description of Changes
Standardizes the query builder API across all three language SDKs (Rust,
TypeScript, C#) for consistency.
**Rust:**
- Rename `Query` struct to `RawQuery`, make `Query` a trait with `fn
into_sql(self) -> String`
- All builder types (`Table`, `FromWhere`, `LeftSemiJoin`,
`RightSemiJoin`) implement `Query<T>` trait
- Views can return `-> impl Query<T>` instead of specifying exact
builder types
- The `#[view]` macro auto-detects `impl Query<T>` and rewrites to
`RawQuery<T>`
- Add `Not` variant to `BoolExpr` with `.not()` method
**TypeScript:**
- Add `ne()` to `ColumnExpression`
- Refactor `BooleanExpr` to `BoolExpr` class with chainable `.and()`,
`.or()`, `.not()` methods
- Make builders valid queries directly (`.build()` deprecated but still
works)
- Deprecate `from()` wrapper — use `tables.person.where(...)` directly
- Merge `query` export into `tables` so table refs are also query
builders
- Add subscription callback form: `subscribe(ctx =>
ctx.from.person.where(...))`
- Unify `useTable` with query builder syntax; deprecate `filter.ts`
**C#:**
- Add `Not()` method to `BoolExpr<TRow>`
- Add `IQuery<TRow>` interface implemented by all builder types
(`Table`, `FromWhere`, `LeftSemiJoin`, `RightSemiJoin`, `Query`)
- Add `ToSql()` to all builder types so `.Build()` is no longer required
- Update `AddQuery` to accept `IQuery<TRow>` instead of `Query<TRow>`
# API and ABI breaking changes
- Rust: `Query<T>` is now a trait (was a struct). The struct is renamed
to `RawQuery<T>`. This is a breaking change for any code that used
`Query<T>` as a type directly.
- TypeScript: `BooleanExpr` is now a `BoolExpr` class (was a
discriminated union type). The `query` export is deprecated in favor of
`tables`.
- C#: `AddQuery` now accepts `Func<QueryBuilder, IQuery<TRow>>` instead
of `Func<QueryBuilder, Query<TRow>>`. Existing `.Build()` calls still
work since `Query<TRow>` implements `IQuery<TRow>`.
# Expected complexity level and risk
3 — Changes touch multiple language SDKs and codegen, but each
individual change is straightforward. The Rust macro rewrite for `impl
Query<T>` detection is the most complex piece. All existing
`.build()`/`.Build()` calls continue to work.
# Testing
- [x] `cargo test -p spacetimedb-query-builder` — 16/16 tests pass
- [x] `cargo check -p spacetimedb` — clean, no warnings
- [x] `cargo check` on views-query, views-sql, views-basic,
views-trapped smoketest modules — all clean
- [x] `cargo test -p spacetimedb-codegen codegen_csharp` — snapshot
updated, passes
- [x] `npm test` (TypeScript) — 101/101 tests pass
- [x] C# QueryBuilder tests — new tests for `Not()`, `IQuery<T>`
interface
- [ ] CI passes
# Description of Changes
Update the Rust client SDK to use the new V2 WebSocket format, and
present the V2 user-facing API.
## Reducer events
### Remove on-reducer callbacks
It's no longer possible to observe reducers called by other clients by
registering callbacks with `ctx.reducers.on_{my_reducer}`. We no longer
code-generate those methods, or the associated
`ctx.reducers.remove_on_{my_reducer}`. Internal plumbing for storing and
invoking those callbacks is also removed.
### Add specific reducer invocation callbacks
In addition to the previous way to invoke reducers,
`ctx.reducers.{my_reducer}(args...)`, we add a method that registers a
callback to run after the reducer is finished. This method has the
suffix `_then`, as in `ctx.reducers.{my_reducer}_then(args...,
callback)`.
The callback will accept two arguments:
- `ctx: &ReducerEventContext`, the same context as was previously passed
to on-reducer callbacks.
- `status: Result<Result<(), String>, InternalError>`, denoting the
outcome of the reducer.
- `Ok(Ok(())` means the reducer committed. This corresponds to
`ReducerOutcome::Ok` or `ReducerOutcome::Okmpty` in the new WS format.
- `Ok(Err(message))` means the reducer returned an "expected" or "user"
error. This corresponds to `ReducerOutcome::Err` in the new WS format.
- `Err(internal_error)` means something went wrong with host execution.
This corresponds to `ReducerOutcome::InternalError` in the new WS
format.
Internally, the SDK stores the callbacks in its `ReducerCallbacks` map.
This is keyed on `request_id: u32`, a number that is generated for each
reducer call (from an `AtomicU32` that we increment each time), and
included in the `ClientMessage::CallReducer` request. The
`ServerMessage::ReducerResult` includes the same `request_id`, so the
SDK pops out of the `ReducerCallbacks` and invokes the appropriate
callback when processing that message.
These new callbacks are very similar to the existing procedure
callbacks.
### The `Event` exposed to row callbacks
Row callbacks caused by a reducer invoked by this client will see
`Event::Reducer`, the same as they would prior to this PR. These
callbacks will be the result of a `ServerMessage::ReducerResult` with
`ReducerOutcome::Ok`. In order to expose the reducer name and arguments
to this event, the client stores them in its `ReducerCallbacks` map,
alongside the callback for when the reducer is complete.
Row callbacks caused by any other reducer, or any non-reducer
transaction, are now indistinguishable to the client. These will see
`Event::Transaction`, which is renamed from the old
`Event::UnknownTransaction`.
### Less metadata in `ReducerEvent`
Some metadata is removed from `ReducerEvent`, as the V2 WebSocket format
no longer publishes it, even to the caller.
## `CallReducerFlags` are removed
All machinery for setting, storing and applying call reducer flags is
removed from the SDK, as the new WS format does not have any non-default
flags.
## Requesting rows in unsubscribe
When sending a `ClientMessage::Unsubscribe`, we always request that the
server include the matching rows in its response
`ServerMessage::UnsubscribeApplied`. This saves us having to update the
SDK to store query sets separately, at least for now. (We'll do that
later.)
## Handling rows
The new SDK does some additional parsing to wrangle rows in the new
WebSocket format into the same internal data structures as before,
rather than re-writing the client cache. (We'll do that later.)
Specifically, parsing of `DbUpdate` is changed so that:
- We parse raw `TransactionUpdate` into the generated `DbUpdate` type,
which requires an additional loop compared to the previous version, to
cope with the new WS format's dividing updates by query set. We define a
function `transaction_update_iter_table_updates` which encapsulates this
nested loop in an iterator.
- We have two new functions for parsing raw `QueryRows` into the
generated `DbUpdate` type, one for when they come from a
`SubscribeApplied`, and the other when they come from an
`UnsubscribeApplied`. `QueryRows` from `SubscribeApplied` translate to a
`DbUpdate` of all inserts, while one from `UnsubscribeApplied` will be
all deletes.
## Legacy subscriptions
"Legacy subscriptions" are removed. These were only used for
`subscribe_to_all_tables`, which as of now is stubbed. I will follow up
with a change to re-implement `subscribe_to_all_tables` by
code-generating a list of all known tables, and having it subscribe to
`select * from {table}` for every table in that list.
## `subscribe_to_all_tables` via a list
Previously, `subscribe_to_all_tables` worked by sending a legacy
subscription with the query `SELECT * FROM *`, which the host had
special handling to expand to subscribing to all tables. As legacy
subscriptions are no longer usable in V2 clients, this can't work.
Instead, we code-generate `SpacetimeModule::ALL_TABLE_NAMES`, a list of
all the known table names. `subscribe_to_all_tables` then maps across
this list to construct a list of queries in the form `SELECT * FROM
{table_name}`, and subscribes to all of those queries. This has the
upside that defining a new table in the module without regenerating
client bindings will no longer result in the client seeing rows of
tables it does not know about and cannot parse.
## Light mode removed
Light mode is no longer meaningful in the V2 WS format, so all code
related to it is removed.
## Internal changes
### Renamed WS messages
The SDK's internal code is updated to account for various renames:
- `QueryId` -> `QuerySetId`, `query_id` -> `query_set_id`.
- `SubscribeMulti` -> `Subscribe`, `UnsubscribeMulti` -> `Unsubscribe`.
## Incidental changes in this PR, not necessary for other client SDKs
### Don't filter out empty ranges in `RowSizeHint`
The Rust implementation of `RowSizeHint` in `BsatnRowList` got regressed
in the base branch to not work with zero-sized rows. This change fixes
that.
# API and ABI breaking changes
Boy howdy is it!
# Expected complexity level and risk
3? Changes ended up being less complicated than I feared, but we do have
some fiddly code here, and we have internal dependencies on the SDK.
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [x] Updated automated test suite.
- Known failures:
- [ ] `subscribe_all_select_star`, which is currently broken because
it's trying to subscribe to rows from private tables. #4241 will fix
this.
---------
Co-authored-by: Jeffrey Dallatezza <jeffreydallatezza@gmail.com>
Co-authored-by: = <cloutiertyler@gmail.com>
# Description of Changes
- Quickstart template `tanstack-ts` and client for TanStack Start
- Add Vue Quickstart Docs
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
- `tanstack-ts` template
<img width="1461" height="898" alt="image"
src="https://github.com/user-attachments/assets/6b7e5473-33c4-4f76-92a7-18607c74422c"
/>
- TanStack Start Quickstart Docs
<img width="1459" height="896" alt="image"
src="https://github.com/user-attachments/assets/b7557498-ff5a-4ce5-9c85-68db943e1b9a"
/>
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [x] Tested the templates locally (e.g. able to add people), works well
for me
# Description of Changes
Document the client query builder api for rust, csharp, and typescript.
Also add/fix some documentation for the module-side query builder.
# API and ABI breaking changes
N/A
# Expected complexity level and risk
0
# Testing
N/A. Just documentation.
---------
Signed-off-by: joshua-spacetime <josh@clockworklabs.io>
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
Modules are like programs, databases are like processes. Your client
connects to a remote database, not a remote module.
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# API and ABI breaking changes
Yep!
# Expected complexity level and risk
2? I made this change with find + replace, and it's possible that I
borked the edit, or missed some reference somehow. It seems unlikely,
however, that this change will have deeper implications we haven't
considered.
# Testing
N/a
# Description of Changes
Haven't changed `schema()` to accept an object yet, maybe that's for a
followup?
Now everything exported from the module must be exported from the
typescript module.
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
# Description of Changes
Adds a Deno quickstart template and documentation.
**Template (`templates/deno-ts/`):**
- `deno.json` with tasks and import map for spacetimedb
- `src/main.ts` using Deno-native APIs (`Deno.stdin`,
`Deno.readTextFile`, `Deno.writeTextFile`, `Deno.env`)
- `spacetimedb/` server module (TypeScript)
- Pre-generated `module_bindings/`
**Documentation
(`docs/docs/00100-intro/00200-quickstarts/00275-deno.md`):**
- Step-by-step quickstart following existing pattern
- Covers project structure, tables/reducers, running the client, CLI
usage
- Documents Deno-specific features: permissions, built-in TypeScript,
import maps, no node_modules
- Explains `--unstable-sloppy-imports` flag (required because generated
bindings use extensionless imports)
# API and ABI breaking changes
None. This is a new template and documentation addition.
# Expected complexity level and risk
**1** - Trivial addition. New template files and documentation only, no
changes to existing code or generator.
# Testing
- [x] Server module publishes successfully
- [x] Bindings generate correctly
- [x] Run `deno task start` and verify connection to SpacetimeDB
- [x] Test interactive CLI commands: add names, `list`, `hello`
# Description of Changes
The PR implements the following updates:
- Create `nuxt-ts` template
- Add Nuxt Quickstart Docs
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
- `nuxt-ts` template
<img width="1446" height="894" alt="image"
src="https://github.com/user-attachments/assets/743a946a-3570-4c0b-823a-c919be722d0a"
/>
- Nuxt Quickstart Docs
<img width="1460" height="898" alt="image"
src="https://github.com/user-attachments/assets/a7014d04-6dc1-4e1d-ac39-051c9ef7c09e"
/>
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
---------
Co-authored-by: = <cloutiertyler@gmail.com>
# Description of Changes
Updated the codegen table/function iteration functions to take in a
parameter to check visibility in all locations for the supported
languages.
- Updated the util.rs functions for iterating tables/functions to check
for a CodegenVisibility enum (IncludePrivate, or OnlyPublic)
- Added a new CodegenOptions struct to pass around the CodegenVisibility
and future flags, defaulted visibility to OnlyPublic
- Updated the CLI to return a list of all private tables not included
(added a TODO to check the --include-private opt):
```bash
Optimising module with wasm-opt...
Build finished successfully.
Skipping private tables during codegen: secret_note, secret_order, secret_person.
Generate finished successfully.
```
# API and ABI breaking changes
Technically API breaking as the private tables will no longer be
available. (GitHub labels are not working at the moment)
# Expected complexity level and risk
1 - Simple change the testing took longer
# Testing
Turns out when you remove private tables you invalidate most of the
module_bindings across the system!
- [x] Rust test SDK for all languages
- [x] C# SDK tests
- [x] C# dotnet tests
- [x] Updated and checked snap files
- [x] Updated Blackholio (Unreal + Unity) module_bindings and tested
- [x] Ran Unreal SDK tests
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
# Description of Changes
Adds a warning prompt for 1.0 -> 2.0 module upgrade path.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
This patch checks a wasm module binary compiled with pre-2.0 bindings
into source control. A smoketest was added that first publishes the the
pre-compiled module and then publishes a new module using the 2.0
bindings in its place.
# Description of Changes
Adds a Remix quickstart template and documentation for SpacetimeDB.
## Template (`templates/remix-ts/`)
- SpacetimeDB module with TypeScript (`spacetimedb/src/index.ts`)
- Remix app with Vite configuration
- SpacetimeDB provider in `app/providers.tsx` with proper SSR/hydration
handling
- Example route (`app/routes/_index.tsx`) demonstrating `useTable` and
`useReducer` hooks
- Pre-generated module bindings in `src/module_bindings/`
## Documentation
(`docs/docs/00100-intro/00200-quickstarts/00175-remix.md`)
- Step-by-step quickstart guide following existing pattern
- Covers project creation with `spacetime dev --template remix-ts`
- Explains project structure, provider pattern, and React hooks usage
- Documents environment variable configuration (`VITE_SPACETIMEDB_HOST`,
`VITE_SPACETIMEDB_DB_NAME`)
## Consistency
- Environment variables follow the same `HOST`/`DB_NAME` naming
convention as other quickstarts
- Documentation structure mirrors Next.js and React quickstarts
- Dev server runs on port 3001 to avoid conflict with SpacetimeDB on
port 3000
# API and ABI breaking changes
None.
# Expected complexity level and risk
1 - Additive change only. New template and documentation, no
modifications to existing functionality.
# Testing
- [ ] Run `spacetime dev --template remix-ts my-remix-app` and verify
app starts
- [ ] Verify SpacetimeDB connection works at http://localhost:3001
- [ ] Test adding a person via the UI form
- [ ] Verify SSR doesn't crash (SpacetimeDB provider defers to
client-side)
- [ ] Check documentation renders correctly in Docusaurus
# Description of Changes
- Updated the chat tutorial to include blocks for C++ server code
- Updated the Python smoketests to allow C++ with the quickstart check
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Small changes to get the C++ modules to be tested through quickstart
# Testing
- [x] Ran the tests locally
# Description of Changes
This PR introduces an **LLM One-Shot App Generation** benchmarking
framework and comprehensive **Cursor rules for SpacetimeDB
development**.
**Cursor Rules (`docs/.cursor/rules/`):**
- `spacetimedb.mdc` - General SpacetimeDB concepts and architecture
- `spacetimedb-csharp.mdc` - C# module and client patterns
- `spacetimedb-rust.mdc` - Rust module development
- `spacetimedb-typescript.mdc` - TypeScript SDK usage
**LLM One-Shot Framework (`tools/llm-oneshot/`):**
- Benchmarking tool to measure how well AI can one-shot SpacetimeDB apps
- Composable prompt system with 12 cumulative feature levels (basic chat
→ full-featured with threading, permissions, presence, etc.)
- Support for 4 tech stacks: TypeScript+SpacetimeDB,
TypeScript+PostgreSQL, Rust+SpacetimeDB, C#+SpacetimeDB
- Additional Cursor rules for deployment, grading, and frontend patterns
**Sample One-Shotted Apps:**
- Multiple chat-app implementations (TypeScript, Rust, C#/MAUI)
- Multiple paint-app implementations (TypeScript, Rust, C#/MAUI)
# API and ABI breaking changes
None - this is a documentation and tooling addition only.
# Expected complexity level and risk
**1** - Trivial addition of documentation, tooling, and example
applications. No changes to core SpacetimeDB functionality. The
`tools/llm-oneshot/` folder is entirely self-contained and the Cursor
rules in `docs/` are purely informational.
# Testing
- [ ] Verified Cursor rules load correctly in IDE
- [ ] Ran one-shot generation with various prompt levels to validate
rules work
- [ ] Sample apps compile and deploy correctly
# Description of Changes
Adds a new Next.js quickstart template and documentation.
**New Template (`templates/nextjs-ts/`):**
- Next.js 15 App Router with TypeScript SpacetimeDB module
- Pre-configured `SpacetimeDBProvider` with client-side connection
handling
- Environment variable support (`NEXT_PUBLIC_SPACETIMEDB_HOST`,
`NEXT_PUBLIC_SPACETIMEDB_DB_NAME`)
- SSR-safe implementation with `"use client"` directives
- Example page demonstrating `useTable` and `useReducer` hooks
- Dev server runs on port 3001 to avoid conflict with SpacetimeDB on
port 3000
- Pre-generated module bindings included
**New Documentation (`docs/.../00200-nextjs.md`):**
- 8-step quickstart consistent with other quickstarts (React,
TypeScript, Rust, C#)
- Covers: project creation, structure, tables/reducers, CLI testing
- Next.js-specific: provider pattern, SSR considerations, env var
configuration, React hooks usage
**Updated `templates-list.json`:**
- Added `nextjs-ts` to highlights and templates list
# API and ABI breaking changes
None.
# Expected complexity level and risk
1 - Adds a new template and docs without modifying existing
functionality.
# Testing
- [ ] Run `spacetime dev --template nextjs-ts my-test-app` and verify
the app starts
- [ ] Navigate to http://localhost:3001 and confirm the UI loads and
connects
- [ ] Add a person via the UI and verify it appears in the list
- [ ] Verify env vars work: set `NEXT_PUBLIC_SPACETIMEDB_URI` and
`NEXT_PUBLIC_SPACETIMEDB_MODULE`
- [ ] Verify the quickstart doc renders correctly in the docs site
- [ ] Confirm Next.js appears in the sidebar after React
# Description of Changes
Adds a Node.js quickstart template and documentation for SpacetimeDB.
## Template (`templates/nodejs-ts/`)
- SpacetimeDB module with TypeScript (`spacetimedb/src/index.ts`)
- Node.js client with interactive CLI (`src/main.ts`)
- File-based token persistence (`.spacetimedb-token`) instead of
localStorage
- Table change callbacks (`onInsert`, `onDelete`)
- Graceful shutdown handlers for `SIGINT`/`SIGTERM`
- Pre-generated module bindings in `src/module_bindings/`
## Documentation
(`docs/docs/00100-intro/00200-quickstarts/00300-nodejs.md`)
- Step-by-step quickstart guide following existing pattern
- Covers project creation with `spacetime dev --template nodejs-ts`
- Explains project structure and client code
- Documents interactive CLI commands (`list`, `hello`, `<name>`)
- Covers Node.js-specific considerations (WebSocket support, token
storage)
- Documents environment variable configuration (`SPACETIMEDB_HOST`,
`SPACETIMEDB_DB_NAME`)
## Consistency
- Environment variables follow the same `HOST`/`DB_NAME` naming
convention as other quickstarts
- Documentation structure mirrors React and Next.js quickstarts
# API and ABI breaking changes
None.
# Expected complexity level and risk
1 - Additive change only. New template and documentation, no
modifications to existing functionality.
# Testing
- [ ] Run `spacetime dev --template nodejs-ts` and verify project
initializes
- [ ] Run `npm run dev` and verify connection to SpacetimeDB
- [ ] Test adding a person by typing a name
- [ ] Test `list` command shows all people
- [ ] Test `hello` command calls reducer (check server logs)
- [ ] Verify token persistence works across restarts
- [ ] Test graceful shutdown with Ctrl+C
- [ ] Check documentation renders correctly
# Description of Changes
Adds a Bun quickstart template and documentation for SpacetimeDB.
## Template (`templates/bun-ts/`)
- SpacetimeDB module with TypeScript (`spacetimedb/src/index.ts`)
- Bun client with interactive CLI (`src/main.ts`)
- Uses Bun-native APIs (`Bun.file()`, `Bun.write()`) for token
persistence
- Uses Bun's native WebSocket and TypeScript support
- Pre-generated module bindings in `src/module_bindings/`
## Documentation
(`docs/docs/00100-intro/00200-quickstarts/00250-bun.md`)
- Step-by-step quickstart guide following existing pattern
- Covers project creation with `spacetime dev --template bun-ts`
- Explains project structure and Bun-specific client code
- Documents environment variable configuration (`SPACETIMEDB_HOST`,
`SPACETIMEDB_DB_NAME`)
- Highlights Bun-specific features (native WebSocket, built-in
TypeScript, `.env` support)
## Consistency
- Environment variables follow the same `HOST`/`DB_NAME` naming
convention as other quickstarts
- Documentation structure mirrors Node.js quickstart
- Interactive CLI mirrors Node.js template behavior
# API and ABI breaking changes
None.
# Expected complexity level and risk
1 - Additive change only. New template and documentation, no
modifications to existing functionality.
# Testing
- [ ] Run `spacetime dev --template bun-ts my-bun-app` and verify app
starts
- [ ] Verify SpacetimeDB connection works via WebSocket
- [ ] Test adding a person via the interactive CLI
- [ ] Verify real-time subscription updates appear in client
- [ ] Check documentation renders correctly in Docusaurus
# Description of Changes
The PR implements the following updates:
- Create a quickstart guide and client support for using SpacetimeDB
directly in browser with script tags
- A template to easily work with/test the implementation and get started
with script tags
The bundle is served via
`https://unpkg.com/spacetimedb@latest/dist/browser.bundle.js`, which
only works after the package is published to npm, therefore to test
locally we can use the `browser-ts` template and local bundle:
1. Build local bundle
```
cd crates/bindings-typescript
pnpm install
pnpm build
```
2. Use local bundle built in template`index.html` (swap the URL from
`unpkg`)
```diff
- <script src="https://unpkg.com/spacetimedb@latest/dist/browser.bundle.js"></script>
+ <script src="../../crates/bindings-typescript/dist/browser.bundle.js"></script>
```
3. Open `browser-ts/index.html` directly in browser along with
`spacetime start` + publish the module `spacetime publish --project-path
spacetimedb browser-ts`
# Screenshots
<img width="1106" height="707" alt="image"
src="https://github.com/user-attachments/assets/715bea26-f54b-42be-97f9-79dcd57d153f"
/>
<img width="1490" height="855" alt="image"
src="https://github.com/user-attachments/assets/2b1aeaf9-22ba-4ae6-bc63-771805b8c2b9"
/>
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
---------
Co-authored-by: = <cloutiertyler@gmail.com>
# Description of Changes
In order to give reviewers a chance to finish in one session the docs
are getting split up for the C++ update. This pass contains the
following section update:
- Tables
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Just documentation additions
# Testing
- [x] Manually tested each block
# Description of Changes
In order to give reviewers a chance to finish in one session the docs
are getting split up for the C++ update. This pass contains the
following section update:
- Unity Blackholio Tutorial
- Unreal Blackholio Tutorial
- Added /demo/Blackholio/server-cpp
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Just documentation additions
# Testing
- [x] Manually tested each block
# Description of Changes
In order to give reviewers a chance to finish in one session the docs
are getting split up for the C++ update. This pass contains the
following section update:
- Functions
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Just documentation additions
# Testing
- [x] Manually tested each block
# Description of Changes
In order to give reviewers a chance to finish in one session the docs
are getting split up for the C++ update. This pass contains the
following section updates:
- Intro
- Databases
- How To
# API and ABI breaking changes
N/A
# Expected complexity level and risk
1 - Just documentation additions
# Testing
- [x] Manually tested each block
# Description of Changes
This adds C++ server bindings (/crate/bindings-cpp) to allow writing C++
20 modules.
- Emscripten WASM build system integration with CMake
- Macro-based code generation (SPACETIMEDB_TABLE, SPACETIMEDB_REDUCER,
etc)
- All SpacetimeDB types supported (primitives, Timestamp, Identity,
Uuid, etc)
- Product types via SPACETIMEDB_STRUCT
- Sum types via SPACETIMEDB_ENUM
- Constraints marked with FIELD* macros
# API and ABI breaking changes
None
# Expected complexity level and risk
2 - Doesn't heavily impact any other areas but is complex macro C++
structure to support a similar developer experience, did have a small
impact on init command
# Testing
- [x] modules/module-test-cpp - heavily tested every reducer
- [x] modules/benchmarks-cpp - tested through the standalone (~6x faster
than C#, ~6x slower than Rust)
- [x] modules/sdk-test-cpp
- [x] modules/sdk-test-procedure-cpp
- [x] modules/sdk-test-view-cpp
- [x] Wrote several test modules myself
- [x] Quickstart smoketest [Currently in progress]
- [ ] Write Blackholio C++ server module
---------
Signed-off-by: Jason Larabie <jason@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
# Description of Changes
Same changes as https://github.com/clockworklabs/SpacetimeDB/pull/4101
but for `connection_id`.
# API and ABI breaking changes
API Breaking
# Expected complexity level and risk
1
# Testing
Pure refactor. Tests and docs have been updated, but no new tests added.
# Description of Changes
Makes the `sender` field on `ViewContext` private and exposes a
`sender()` method. Does the same for `ReducerContext` and
`ProcedureContext`.
The purpose of this change: So that the host can determine if/when a
view invokes or reads the `sender`.
Currently, because `sender` is a field, the host assumes that it is
always read. This means views must be materialized per client, even if
the view doesn't actually depend on `sender`, resulting in data
duplication.
The initial solution for this problem was `AnonymousViewContext` which
doesn't have a `sender` field. The better solution is to make `sender` a
method so that it can call into the host and record when it's actually
invoked.
Note, this patch only updates the module API, so the current
implementation does not change. `ViewContext` views are still duplicated
across clients. Changing this requires a new host syscall and for
`sender()` to invoke that syscall. This however is backwards compatible
and can be done anytime after the module APIs for the other languages
(C#, TypeScript, C++) are updated.
Also note that `ReducerContext` and `ProcedureContext` were updated
purely for consistency. There are currently no plans to track reads of
`sender` in these contexts.
# API and ABI breaking changes
Breaks the rust module api.
# Expected complexity level and risk
1
# Testing
N/A
# Description of Changes
When reading the docs, I noticed that even though TypeScript is included
in most of the examples, the text at the top of the 'Key Architecture'
section doesn't mention it as a language that can be used to write
Modules.
This change simply adds TypeScript to the list of languages that can be
used to write Modules.
This is my first ever pull request, so my apologies if this change is
considered too small.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
I've not done any testing considering the size of the changes.
Signed-off-by: Luuk Domhof <60610562+ExpLuuk@users.noreply.github.com>
Co-authored-by: Zeke Foppa <196249+bfops@users.noreply.github.com>
# Description of Changes
Tiny addition to the llm context to explain that maincloud publishing is
free of charge
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
Ran claude code with updated context and it performed better in the
publishing step
# Description of Changes
Update ai rules general mdc file to explain deployment and maincloud
# API and ABI breaking changes
No
# Expected complexity level and risk
1
# Testing
Ran with claudecode
Implements the client-api changes for the organizations feature.
The interesting part of this PR are the `teams` smoketests.
There is one subtlety with deletion.
Note that I haven't (yet) covered the interaction between collaborators
and organization existing for the same database.
# Description of Changes
The PR implements the following updates:
- Create Svelte framework sdk/integration
- Add Svelte Quickstart Docs
- Create `svelte-ts` template
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# Screenshots
- `svelte-ts` template
<img width="1511" height="863" alt="Screenshot1"
src="https://github.com/user-attachments/assets/f266dc63-228c-4bff-96f6-b780ce53167f"
/>
- Svelte Quickstart Docs
<img width="1451" height="893" alt="Screenshot2"
src="https://github.com/user-attachments/assets/3456a60b-60d7-4232-94fc-152a020f675b"
/>
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
---------
Co-authored-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
# Description of Changes
Addresses https://github.com/clockworklabs/SpacetimeDB/issues/4131.
I did not thread the new option into other commands such as `spacetime
init` (they just retain the previous behavior). I think this is a
relatively niche use case, and it's easy to work around either way (by
just using `spacetime login` first) so I'd wait until someone asks us to
thread it through to other places.
# API and ABI breaking changes
None
# Expected complexity level and risk
1
# Testing
- [x] Ran `spacetime login --no-browser` and saw that it didn't open a
browser
- [x] Ran `spacetime login` and saw that it still opened a browser
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Two documentation improvements:
1. **Reducers documentation**: Clarified that using global/static
variables in reducers is **undefined behavior**, not just "values won't
persist". Added six specific reasons why this is undefined:
- Fresh execution environments
- Module updates
- Concurrent execution
- Crash recovery
- Non-transactional updates
- Replay safety
2. **Access permissions documentation**: Replaced the "Combining Both
Techniques" example that used indexes on Option fields (which
SpacetimeDB doesn't support) with a working example that filters by a
required `department` field instead.
# API and ABI breaking changes
None. Documentation only.
# Expected complexity level and risk
1 - Documentation changes only.
# Testing
- [ ] Verify the reducers warning is clear and accurate
- [ ] Verify the access permissions example compiles and makes sense
---------
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
# Description of Changes
<!-- Please describe your change, mention any related tickets, and so on
here. -->
Version upgrade to `v1.12.0`.
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
None
# Expected complexity level and risk
1 - this is just a version upgrade
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
The testsuite failures are fixed by
https://github.com/clockworklabs/SpacetimeDB/pull/4120
- [x] License has been properly updated including version number and
date
- [x] CI passes
---------
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
The PR implements the following updates:
- Create Vue framework sdk
- Add Vue Quickstart Docs
- Create `vue-ts` template
# Screenshots
- `vue-ts` template
<img width="1512" height="862" alt="Screenshot"
src="https://github.com/user-attachments/assets/15c8209b-ec7f-4f4a-a5b4-5174ddd068be"
/>
- Vue Quickstart Docs
<img width="1392" height="854" alt="image"
src="https://github.com/user-attachments/assets/57650232-81fa-43d3-be5a-135aa1799f05"
/>
<!-- Please describe your change, mention any related tickets, and so on
here. -->
# API and ABI breaking changes
<!-- If this is an API or ABI breaking change, please apply the
corresponding GitHub label. -->
# Expected complexity level and risk
<!--
How complicated do you think these changes are? Grade on a scale from 1
to 5,
where 1 is a trivial change, and 5 is a deep-reaching and complex
change.
This complexity rating applies not only to the complexity apparent in
the diff,
but also to its interactions with existing and future code.
If you answered more than a 2, explain what is complex about the PR,
and what other components it interacts with in potentially concerning
ways. -->
# Testing
<!-- Describe any testing you've done, and any testing you'd like your
reviewers to do,
so that you're confident that all the changes work as expected! -->
- [ ] <!-- maybe a test you want to do -->
- [ ] <!-- maybe a test you want a reviewer to do, so they can check it
off when they're satisfied. -->
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Try fixing this again? It seems to pass on PRs if re-run.
# API and ABI breaking changes
None.
# Expected complexity level and risk
1
# Testing
- [x] It passes on this PR now 🤷
---------
Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
the TS reference was slightly missing. you need assign a variable to the
reducer to call it cross context
# Description of Changes
slight reference fix
Signed-off-by: kormann <49917710+DKormann@users.noreply.github.com>
# Description of Changes
This PR renames the templates to always use shorthand for the language,
specify a framework (or console) if necessary, and shorten the naming in
general
# Expected complexity level and risk
1
# Testing
I've tested generating templates manually
---------
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
# Description of Changes
Adds TypeScript as a third language for LLM benchmark tests alongside
Rust and C#, and fixes table naming convention mismatches.
**TypeScript Support:**
- Added `Lang::TypeScript` variant with camelCase naming conventions
- Created TypeScript project template (`templates/typescript/server/`)
with package.json, tsconfig.json, and index.ts
- Added TypeScript publisher that uses `spacetime build` and `spacetime
publish`
- Created 22 TypeScript task prompts and golden answer files for all
benchmark tests
- Updated prompt discovery to find `tasks/typescript.txt` files
**Table Naming Fix:**
- Standardized on singular table names across all languages:
- Rust: `user` (snake_case singular)
- C#: `User` (PascalCase singular)
- TypeScript: `user` (camelCase singular)
- Updated `table_name()` helper to convert singular names to appropriate
case per language
- Updated all spec.rs files to use `table_name("user", lang)` instead of
hardcoded `"users"`
**CI/Hashing Improvements:**
- Added `compute_processed_context_hash()` for language-specific hash
computation after tab filtering
- Updated CI check to verify both `rustdoc_json` and `docs` modes for
Rust
- Fixed `--hash-only` mode to skip golden builds
# API and ABI breaking changes
None - these are internal benchmark tooling changes only.
# Expected complexity level and risk
**Complexity: 2**
The changes add a new language following existing patterns for Rust and
C#. The table naming fixes are straightforward find-and-replace style
updates. Low risk since this only affects the benchmark tooling, not the
core SpacetimeDB codebase.
# Testing
- [x] `cargo build -p xtask-llm-benchmark` compiles successfully
- [x] All 22 TypeScript golden modules build and publish successfully
- [x] Rust and C# benchmarks unaffected by changes
---------
Signed-off-by: Tyler Cloutier <cloutiertyler@users.noreply.github.com>
Co-authored-by: clockwork-labs-bot <clockwork-labs-bot@users.noreply.github.com>
Co-authored-by: John Detter <4099508+jdetter@users.noreply.github.com>