v1.9.0

clockworklabs/SpacetimeDBv1.9.0Nov 21, 2025by cloutiertyler

AI Summary

This release adds Project Collaborators for team management and introduces a major TypeScript API update that unifies server and client APIs with Zod-like type builders.

Key Highlights

  • Project Collaborators feature for team management on Maincloud.
  • TypeScript API update: unified server/client API, TypeBuilder exports, and `Infer<>` types.
  • React SDK improvements including `useReducer` hook and tuple return from `useTable`.
  • C# `ConfirmedReads` configuration.

Breaking Changes

  • Table accessor names converted to camelCase
  • Removal of `InferTypeOfRow` (use `Infer` instead)
  • Removal of `MyTypeVariants` for sum types
  • Reducer arguments passed as objects instead of variadic params
  • `count()` returns `bigint` instead of `number`

New Features

  • Project Collaborators
  • TypeScript API unification
  • React SDK updates
  • ProcedureContext::with_tx

Full Release Notes

Today we have a long overdue feature we're releasing, project collaborators! 👯 

## Project Collaborators

Now you can invite other members of your team to join your projects that you deploy to Maincloud.

<img width="1127" height="553" alt="image" src="https://github.com/user-attachments/assets/865db707-f0ca-4f64-a562-9b302e3947e8" />

In order to add collaborators, navigate to your project on the website and go to `Settings > Collaborators`, and then press `Add People` to add a new collaborator to your project. 

Depending on the role you assign the user, they will be able to perform actions that were previously only possible for the database owner to run, including updating the module, viewing logs, and editing tables.

## TypeScript (Beta) - API Update

We also have the first major update to our TypeScript API. This change dramatically improves usability in a few key areas and fixes some critical bugs in the TypeScript and React SDKs.

> [!IMPORTANT]
> This update also comes with a few breaking changes to the TypeScript API, which are detailed below. In general, we will try to minimize the number of changes to the existing API, but while TypeScript is in Beta we will be making a few important changes until we stabilize the API completely.

### TypeScript Modules

TypeScript modules only get a modest change from the previous API:

- Table accessor names and index accessor names are converted to `camelCase` on the `ctx`, so if your table name is `foo_bar`, the accessor changes from `ctx.db.foo_bar` to `ctx.db.fooBar`. This allows you to use whatever table name you want for your tables without running afoul of TypeScript linters.
- `Infer<>` now also does `InferTypeOfRow<>` if applicable which means you can forget about `InferTypeOfRow` and just use `Infer` in all cases to get the type of a type builder.

### TypeScript SDK

The TypeScript SDK has now been unified with the API of server modules. Code generation now uses the same types and functions that you use on the server. The eventual goals is to allow you to use your actual server types in your TypeScript client without needing to do any code generation. This leads to the following changes:

- All types exported by generated files are now `TypeBuilder`s, meaning that if you were previously using a type from a generated file, you will now have to do `const x: Infer<typeof MyType>` instead of `const x: MyType`. This may seem like an inconvenience, but it vastly improves a lot of the other APIs and is very flexible to extend and is inspired by the very powerful [Zod](https://zod.dev/) library.
- We no longer generate and export `MyTypeVariants` for sum types (these are now accessed by `Infer<typeof MyType.variants.myVariant>`)
- Your `module_bindings` now export a `tables` object with references to all the `TableDef`s
- Your `module_bindings` now export a `reducers` object with references to all the `ReducerDef`s
- On the client `my_table.iter()` now returns `IterableIterator` instead of an `Array`
- `MyType.getTypeScriptAlgebraicType()` has been replaced with `MyType.algebraicType`
- Reducers are now called with the same format on the server and clients. e.g. `ctx.reducers.createPlayer(argA, argB)` -> `ctx.reducers.createPlayer({ argA, argB })`
- Reducer callbacks now also take arguments the same way: `ctx.reducers.onCreatePlayer(ctx, argA, argB)` -> `ctx.reducers.onCreatePlayer(ctx, { argA, argB })` & `ctx.reducers.removeOnCreatePlayer(ctx, argA, argB)` -> `ctx.reducers.removeOnCreatePlayer(ctx, { argA, argB })`
- `count()` now returns a `bigint` instead of a number to match the server API e.g. `myTable.count(): number` -> `myTable.count(): bigint`. This may be changed in the future as it is unlikely that you will have a table with more than 2^53 rows.

## Notable things that did not change:
- `MyType.serialize(writer: BinaryWriter, value: Infer<typeof MyType>)` and `MyType.deserialize(reader: BinaryReader): Infer<typeof MyType>` are still supported exactly as before.
- The `MyType.MyVariant(...)` constructor function on sum types is still present, but implemented with the private `MyType.create('MyVariant', ...)`. We could choose to move away from this API later if we didn't like the variants polluting the namespace

> [!WARNING]
> You will need to regenerate your module bindings for your TypeScript clients with the latest version of the `spacetime` CLI tool.

### React SDK

The React SDK gets a major improvement in both usability and correctness.

- `useSpacetimeDB()` no longer takes type parameters
- `useSpacetimeDB()` now returns a `ConnectionState`. All fields on the `ConnectionState` are not React state and will cause a rerender any time they change
- `useTable()` now takes a `TableDef` parameter and type params are inferred
- `useTable()` now just returns a tuple with the first element being an `Array` instead of a object with `{ rows }`
- Added a `useReducer()` React hook

So now you can write this in your React client:

```ts
  import { reducers, tables } from "./module_bindings";

  const { identity, isActive: connected } = useSpacetimeDB();
  const setName = useReducer(reducers.setName);
  const sendMessage = useReducer(reducers.sendMessage);
  const [onlineUsers] = useTable(tables.user, where(eq('online', true)));
```

The API for using a view is the same as using a table:

```ts
  const [myViewRows] = useTable(tables.myView);
```

## What's Changed
* [teams 4/5] SQL authorization by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3525
* CI - TypeScript quickstart works properly in the face of version bumps by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3634
* [TS] Specify the name of a view in an options object by @coolreader18 in https://github.com/clockworklabs/SpacetimeDB/pull/3642
* Reference docs for views by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3641
* Update views on auto-migrate by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3631
* Upgrade to version 1.8.0 by @jdetter in https://github.com/clockworklabs/SpacetimeDB/pull/3633
* [teams 5/5] Identity routes by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3526
* PR merge discord post includes all non-successful checks by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3594
* Switch Internal Tests to reuse CI job by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3625
* Tweak DNS resolution error message by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3647
* Fix noisy Discord notifications on PR merge by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3650
* CI - Fix "Check that packages are publishable" check by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3660
* Scheduled reducer: use timestamp from reducer params for next run by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3657
* client-api: Make `ControlStateReadAccess` an async trait by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3357
* Remove the middle man thread the JS worker thread by @Centril in https://github.com/clockworklabs/SpacetimeDB/pull/3577
* Use new runner for testsuite by @jdetter in https://github.com/clockworklabs/SpacetimeDB/pull/3656
* CI - Cancel internal tests if cancelled by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3674
* CI - Ping PR author directly if checks fail by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3671
* Fix the basic-rust client template for CLI's init command by @drogus in https://github.com/clockworklabs/SpacetimeDB/pull/3646
* C#: Add confirmed reads configuration by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3282
* Fix test with change on defaults by @mamcx in https://github.com/clockworklabs/SpacetimeDB/pull/3683
* commitlog: Change default max-records-in-commit to 1 by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3681
* Fix `spacetime generate` running `dotnet format` in the wrong directory by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3687
* CI - Fix empty lookup by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3693
* fix plan caching for client-specific views by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3672
* Unifies server module library and client SDK for TypeScript (and fixes several bugs) by @cloutiertyler in https://github.com/clockworklabs/SpacetimeDB/pull/3559
* Fix #3687 by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3692
* Adds flag to publish to allow clearing on migration conflict. by @cloutiertyler in https://github.com/clockworklabs/SpacetimeDB/pull/3601
* Client codegen fixes for views by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3690
* CI - Cache more of our build outputs by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3521
* Add `ProcedureContext::with_tx` by @Centril in https://github.com/clockworklabs/SpacetimeDB/pull/3638
* `anyonymousView` -> `anonymousView` by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3697
* Add check for .env.local and module bindings generations to only write on changes by @aceysmith in https://github.com/clockworklabs/SpacetimeDB/pull/3604
* Move typescript tests to new runner by @jdetter in https://github.com/clockworklabs/SpacetimeDB/pull/3696
* Add `smoketests/requirements.txt` by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3701
* Fix C# module bindings codegen for namespaces with view dispatcher by @JasonAtClockwork in https://github.com/clockworklabs/SpacetimeDB/pull/3668
* Fix running `smoketests --list` by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3700
* Views: ephemeral tables by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3670
* Change `spacetime_worker_wasm_instance_errors_total` metric's labels by @drogus in https://github.com/clockworklabs/SpacetimeDB/pull/3614
* Views: cleanup unsubscribed views by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3651
* Export __call_view__ in C# by @rekhoff in https://github.com/clockworklabs/SpacetimeDB/pull/3691
* Views: blocking thread for views cleanup by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3707
* Add extra claims to v1/identity/websocket-token by @JulienLavocat in https://github.com/clockworklabs/SpacetimeDB/pull/3705

## New Contributors
* @aceysmith made their first contribution in https://github.com/clockworklabs/SpacetimeDB/pull/3604

**Full Changelog**: https://github.com/clockworklabs/SpacetimeDB/compare/v1.8.0...v1.9.0