v1.11.0

clockworklabs/SpacetimeDBv1.11.0Dec 9, 2025by jdetter

AI Summary

This release introduces a typed Query Builder API for Rust and TypeScript modules, enabling more expressive views that can iterate or scan tables and perform complex queries.

Key Highlights

  • Typed Query Builder API with operators like `.where()`, `.leftSemijoin()`, and `.rightSemijoin()`.
  • Allows views to iterate or scan tables, something previously unavailable.
  • Bug fixes for `--delete-data=on-conflict` flag and publishing with `-c`.
  • Fixes for `on_insert` and `on_delete` firing correctly for per-client views.

New Features

  • Query Builder for Rust and TypeScript modules
  • Query operators (where, left_semijoin, right_semijoin)
  • View rewrite for delta tables

Full Release Notes

Today we've released query builders for Rust and TypeScript modules. The purpose of the query builder API is so that you can write views that will take advantage of the unique performance guarantees of SpacetimeDB's query engine, particularly for realtime subscription updates.

The query builder also now allows you to iterate or scan a table in a view, something that previously wasn't possible using only the index accessors exposed by `ViewContext` and `AnonymousViewContext`.

The query builder exposes the following query operators:
* `.where()` 
    Used for filtering. Equivalent to a `WHERE` condition in SQL.
* `.leftSemijoin()`
    Equivalent to an inner join in sql where a row is return from the `lhs` only if it matches with a row on the `rhs`.
* `.rightSemijoin()`
    Equivalent to an inner join in sql where a row is return from the `rhs` only if it matches with a row on the `lhs`.

## Examples (Rust)
```rust
use spacetimedb::{Identity, Query, Table, ViewContext, AnonymousViewContext};

#[spacetimedb::table(name = player_state)]
pub struct PlayerState {
    #[unique]
    player_id: u64,
    online: bool,
}

#[spacetimedb::table(name = player_internal)]
pub struct Player {
    #[auto_inc]
    #[primary_key]
    id: u64,
    #[unique]
    identity: Identity,
    name: String,
    #[index(btree)]
    age: u8,
}

#[spacetimedb::table(name = moderator_internal)]
pub struct Moderator {
    #[unique]
    player_id: u64,
}

/// Returns all players.
/// Equivalent to `SELECT * FROM player_internal`.
#[spacetimedb::view(name = player, public)]
fn player(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from.player_internal().build()
}

/// Returns the caller's player.
/// Equivalent to `SELECT * FROM player_internal WHERE "identity" = :sender`.
#[spacetimedb::view(name = my_player, public)]
fn my_player(ctx: &ViewContext) -> Query<Player> {
    ctx.from.player_internal().r#where(|p| p.identity.eq(ctx.sender)).build()
}

/// Returns only online players.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online
/// ```
#[spacetimedb::view(name = online_player, public)]
fn online_player(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from
        .player_state()
        .r#where(|p| p.online.eq(true))
        .right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
        .build()
}

/// Returns only the caller's player if online.
/// Equivalent to:
/// ```sql
/// SELECT q.*
/// FROM player_state p JOIN player_internal q ON p.player_id = q.id
/// WHERE p.online AND q.identity = :sender
/// ```
#[spacetimedb::view(name = my_online_player, public)]
fn my_online_player(ctx: &ViewContext) -> Query<Player> {
    ctx.from
        .player_state()
        .r#where(|p| p.online.eq(true))
        .right_semijoin(ctx.from.player_internal(), |(p, q)| p.player_id.eq(q.id))
        .r#where(|p| p.identity.eq(ctx.sender))
        .build()
}

/// Returns the moderators.
/// Equivalent to:
/// ```sql
/// SELECT p.* FROM player_internal p JOIN moderator_internal m ON p.id = m.player_id
/// ```
#[spacetimedb::view(name = moderator, public)]
fn moderator(ctx: &AnonymousViewContext) -> Query<Player> {
    ctx.from
        .player_internal()
        .left_semijoin(ctx.from.moderator_internal(), |(p, m)| p.id.eq(m.player_id))
        .build()
}
```

## Examples (TypeScript)
```ts
import { schema, table, t, type RowObj } from 'spacetimedb/server';

const playerState = table('playerState', {
  playerId: t.u64().unique(),
  online: t.bool(),
});

const playerInternal = table('playerInternal', {
  id: t.u64().primaryKey().autoInc(),
  identity: t.identity().unique(),
  name: t.string(),
  age: t.u8().index('btree'),
});

const spacetimedb = schema(playerState, playerInternal);

spacetimedb.view(
  { name: 'my_online_player', public: true },
  t.array(playerInternal.row()),
  ctx => {
    return ctx.from.playerState
      .where(p => p.online.eq(true))
      .rightSemijoin(ctx.from.playerInternal, (p, q) => p.playerId.eq(q.id))
      .where(p => p.identity.eq(ctx.sender))
      .build();
  }
);
```

## Bug Fixes
* Fixes an [issue](https://github.com/clockworklabs/SpacetimeDB/issues/3729) with the `--delete-data=on-conflict` flag of `spacetimedb publish`
* Fixes an issue where databases were returning 400/500 errors after publishing with `-c`
* Fixes an [issue](https://discord.com/channels/1037340874172014652/1444072983168815207/1444072983168815207) where `on_insert` and `on_delete` were not firing correctly for per-client (ViewContext) views

## What's Changed
* Delete duplicated docs folders by @gefjon in https://github.com/clockworklabs/SpacetimeDB/pull/3780
* Fixes reported issues with the TypeScript SDK by @cloutiertyler in https://github.com/clockworklabs/SpacetimeDB/pull/3737
* Fix some typescript issues by @coolreader18 in https://github.com/clockworklabs/SpacetimeDB/pull/3775
* Split Unity and C# tests into separate jobs by @jdetter in https://github.com/clockworklabs/SpacetimeDB/pull/3779
* Update typescript package size limits by @jdetter in https://github.com/clockworklabs/SpacetimeDB/pull/3786
* Add docs for procedures by @gefjon in https://github.com/clockworklabs/SpacetimeDB/pull/3766
* Actually report reducer fuel used by @drogus in https://github.com/clockworklabs/SpacetimeDB/pull/3799
* Fix view rewrite for delta tables by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3801
* Remove race condition from sdk test by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3804
* Implement DbContext for AnonymousViewContext and ViewContext by @tamaro-skaljic in https://github.com/clockworklabs/SpacetimeDB/pull/3787
* Fixes docs links by @cloutiertyler in https://github.com/clockworklabs/SpacetimeDB/pull/3803
* C# Views - Use Name from ViewAttribute instead of Method Name by @chutch1122 in https://github.com/clockworklabs/SpacetimeDB/pull/3792
* Remove duplicate assertSql in smoke test by @mamcx in https://github.com/clockworklabs/SpacetimeDB/pull/3588
* Docs: Update docs nav height to 56px by @clockwork-tien in https://github.com/clockworklabs/SpacetimeDB/pull/3788
* [TS] Fix `development` exports breaking NextJS by @kistz in https://github.com/clockworklabs/SpacetimeDB/pull/3796
* [TS] Call registerType for procedure params by @coolreader18 in https://github.com/clockworklabs/SpacetimeDB/pull/3806
* CI - Skip the Unity testsuite on external PRs by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3805
* Bump versions to 1.11.0 by @bfops in https://github.com/clockworklabs/SpacetimeDB/pull/3808
* Added and tested procedure docs for Unreal C++ & Unreal Blueprint by @JasonAtClockwork in https://github.com/clockworklabs/SpacetimeDB/pull/3810
* Update view ABI to support returning queries by @jsdt in https://github.com/clockworklabs/SpacetimeDB/pull/3685
* [Rust] Module-side query builder types by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3797
* [Rust] update module bindings to use new view abi by @joshua-spacetime in https://github.com/clockworklabs/SpacetimeDB/pull/3819
* Update wasmtime to v39 by @coolreader18 in https://github.com/clockworklabs/SpacetimeDB/pull/3818
* [Rust] Query builder Integration. by @Shubham8287 in https://github.com/clockworklabs/SpacetimeDB/pull/3823
* Store `SubscriptionMetrics` for `Update`, `Subscribe`, `Unsubscribe` in `ModuleSubscriptions` by @Centril in https://github.com/clockworklabs/SpacetimeDB/pull/3821
* smoketests: Adjust test_enable_disable_replication test by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3822
* [TS] Implement TextEncoder/TextDecoder with native code by @coolreader18 in https://github.com/clockworklabs/SpacetimeDB/pull/3800
* Debug "stuck module" issue by @kim in https://github.com/clockworklabs/SpacetimeDB/pull/3813
* Fixes issues with `--delete-data=on-conflict` by @cloutiertyler in https://github.com/clockworklabs/SpacetimeDB/pull/3730
* Add a typescript query builder for views by @jsdt in https://github.com/clockworklabs/SpacetimeDB/pull/3812

## New Contributors
* @tamaro-skaljic made their first contribution in https://github.com/clockworklabs/SpacetimeDB/pull/3787
* @chutch1122 made their first contribution in https://github.com/clockworklabs/SpacetimeDB/pull/3792
* @kistz made their first contribution in https://github.com/clockworklabs/SpacetimeDB/pull/3796

**Full Changelog**: https://github.com/clockworklabs/SpacetimeDB/compare/v1.10.0...v1.11.0