Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
394b78b
Fix CI push failure by rebasing before push
cloutiertyler Jan 17, 2026
392802c
Standardize table names to singular for LLM benchmarks
cloutiertyler Jan 17, 2026
f2acff2
Add processed context hashing and update CI check logic
cloutiertyler Jan 17, 2026
8d3d414
Small typo fix
cloutiertyler Jan 17, 2026
ec73cb5
Updated llm benchmarks
cloutiertyler Jan 17, 2026
9714a89
Added TypeScript llm benchmark tests
cloutiertyler Jan 20, 2026
c5f9705
Small fix
cloutiertyler Jan 20, 2026
6429a20
cargo fmt
cloutiertyler Jan 20, 2026
fe59ff7
Update LLM benchmark results
clockwork-labs-bot Jan 20, 2026
f20e198
CI: Build llm_benchmark tool from master for consistent hash checking
cloutiertyler Jan 20, 2026
e31ace7
Fixed some more plurals
cloutiertyler Jan 20, 2026
59cb826
Fix WASI SDK tar extraction race condition in parallel C# builds
cloutiertyler Jan 20, 2026
02a6448
Update LLM benchmark results
clockwork-labs-bot Jan 20, 2026
8340d2d
Fixed lint
cloutiertyler Jan 20, 2026
ac6890a
Fix documentation issues in quickstarts, column-types, and access-per…
cloutiertyler Jan 20, 2026
5f6856c
Add warning about global/static variables not persisting in reducers
cloutiertyler Jan 20, 2026
5d0e223
Add File Storage documentation page
cloutiertyler Jan 20, 2026
b0cd9c7
Improve subscriptions documentation with Quick Start section
cloutiertyler Jan 20, 2026
eeabea2
Update LLM benchmark results
clockwork-labs-bot Jan 20, 2026
1f601f6
Apply suggestions from code review
cloutiertyler Jan 21, 2026
721eae2
Update LLM benchmark results
clockwork-labs-bot Jan 21, 2026
ce6042a
Clarify that global/static variables are undefined behavior, not just…
cloutiertyler Jan 20, 2026
589c2ea
Replace Option index example with department-based example
cloutiertyler Jan 20, 2026
765bd43
Fix incorrect paths in Unity tutorial
cloutiertyler Jan 20, 2026
580dca7
Update file storage size recommendations and fix Unity tutorial paths
cloutiertyler Jan 20, 2026
ab3b027
Reduce git diff noise in benchmark details.json
cloutiertyler Jan 20, 2026
e4f38ba
Document reducer and procedure interactions
cloutiertyler Jan 21, 2026
748485e
Fix schedule-tables examples to compile
cloutiertyler Jan 21, 2026
849e709
Clarify Rust pub modifier vs SpacetimeDB table visibility
cloutiertyler Jan 21, 2026
be2046e
Add S3 upload examples and C# procedure support
cloutiertyler Jan 21, 2026
b879a57
Update LLM benchmark results
clockwork-labs-bot Jan 21, 2026
b8c5230
Merge appendix content into auto-increment page and delete appendix
cloutiertyler Jan 21, 2026
fa8c4ba
Merge origin/master into tyler/claude-docs-6
cloutiertyler Jan 21, 2026
053c489
Add TypeScript support to LLM benchmark CI and analysis
cloutiertyler Jan 22, 2026
579cb51
Use relative paths in context to fix hash computation across environm…
cloutiertyler Jan 22, 2026
d7870f8
Merge origin/master into tyler/claude-docs-6
cloutiertyler Jan 22, 2026
fd4d556
Update LLM benchmark results
clockwork-labs-bot Jan 22, 2026
9f1742c
Apply suggestions from code review
cloutiertyler Jan 22, 2026
f72fe8b
Add missing C# tabs to procedures documentation
cloutiertyler Jan 22, 2026
667b984
Fix C# procedure snippets to use correct API patterns
cloutiertyler Jan 22, 2026
38d514f
Fix C# procedure return type in file storage docs
cloutiertyler Jan 22, 2026
176b50e
Add C# example for pre-signed URL flow in file storage docs
cloutiertyler Jan 22, 2026
b62238c
Add missing Module class wrapper to C# examples in schedule-tables docs
cloutiertyler Jan 22, 2026
70960ab
Merge branch 'master' into tyler/claude-docs-6
cloutiertyler Jan 22, 2026
842ac21
Fixed plurals in llm test
cloutiertyler Jan 22, 2026
3709b36
Update LLM benchmark results
clockwork-labs-bot Jan 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -495,16 +495,16 @@ The `spacetime` CLI has built in functionality to let us generate C# types that
directory run the following command:
</TabItem>
<TabItem value="rust" label="Rust">
Let's generate our types for our module. In the `blackholio/server-rust`
Let's generate our types for our module. In the `blackholio/spacetimedb`
directory run the following command:
</TabItem>
</Tabs>

```sh
spacetime generate --lang csharp --out-dir ../client-unity/Assets/autogen # you can call this anything, I have chosen `autogen`
spacetime generate --lang csharp --out-dir ../Assets/autogen
```

This will generate a set of files in the `client-unity/Assets/autogen` directory which contain the code generated types and reducer functions that are defined in your module, but usable on the client.
This will generate a set of files in the `Assets/autogen` directory which contain the code generated types and reducer functions that are defined in your module, but usable on the client.

```
├── Reducers
Expand All @@ -525,7 +525,7 @@ This will generate a set of files in the `client-unity/Assets/autogen` directory
└── SpacetimeDBClient.g.cs
```

This will also generate a file in the `client-unity/Assets/autogen/SpacetimeDBClient.g.cs` directory with a type aware `DbConnection` class. We will use this class to connect to your database from Unity.
This will also generate a file in the `Assets/autogen/SpacetimeDBClient.g.cs` directory with a type aware `DbConnection` class. We will use this class to connect to your database from Unity.

> IMPORTANT! At this point there will be an error in your Unity project. Due to a [known issue](https://docs.unity3d.com/6000.0/Documentation/Manual/csharp-compiler.html) with Unity and C# 9 you need to insert the following code into your Unity project.
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ This is a simple reducer that takes the movement input from the client and appli

</TabItem>
<TabItem value="rust" label="Rust" >
Let's start by building out a simple math library to help us do collision calculations. Create a new `math.rs` file in the `server-rust/src` directory and add the following contents. Let's also move the `DbVector2` type from `lib.rs` into this file.
Let's start by building out a simple math library to help us do collision calculations. Create a new `math.rs` file in the `spacetimedb/src` directory and add the following contents. Let's also move the `DbVector2` type from `lib.rs` into this file.

```rust
use spacetimedb::SpacetimeType;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ SpacetimeDB does not support nested transactions. When one reducer calls another
The `#[auto_inc]` sequence generator is not transactional:
- Sequence numbers are allocated even if a transaction rolls back
- This can create gaps in your sequence
- See [SEQUENCE documentation](/reference/appendix#sequence) for details
- See [Auto-Increment](/tables/auto-increment#crash-recovery) for details

## Related Topics

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -383,7 +383,24 @@ spacetimedb.procedure(
<TabItem value="csharp" label="C#">

```csharp
// C# procedure support coming soon
// Add #pragma warning disable STDB_UNSTABLE at file top

[SpacetimeDB.Procedure]
public static string FetchData(ProcedureContext ctx, string url)
{
var result = ctx.Http.Get(url);
if (result is Result<HttpResponse, HttpError>.OkR(var response))
{
var data = response.Body.ToStringUtf8Lossy();
ctx.WithTx(txCtx =>
{
txCtx.Db.Cache.Insert(new Cache { Data = data });
return 0;
});
return data;
}
return "";
}
```

</TabItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -404,13 +404,22 @@ Reducers run in an isolated environment and **cannot** interact with the outside

If you need to interact with external systems, use [Procedures](/functions/procedures) instead. Procedures can make network calls and perform other side effects, but they have different execution semantics and limitations.

:::warning Global and Static Variables Do Not Persist
Global variables, static variables, and module-level state do **not** persist across reducer calls. Each reducer invocation runs in a fresh execution environment. Any data stored in global or static variables will be lost when the reducer completes.
:::warning Global and Static Variables Are Undefined Behavior
Relying on global variables, static variables, or module-level state to persist across reducer calls is **undefined behavior**. SpacetimeDB does not guarantee that values stored in these locations will be available in subsequent reducer invocations.

Always store persistent state in tables. If you need to cache computed values or maintain state across invocations, use a table to store that data.
This is undefined for several reasons:

1. **Fresh execution environments.** SpacetimeDB may run each reducer in a fresh WASM or JS instance.
2. **Module updates.** Publishing a new module creates a fresh execution environment. This is necessary for hot-swapping modules while transactions are in flight.
3. **Concurrent execution.** SpacetimeDB reserves the right to execute multiple reducers concurrently in separate execution environments (e.g., with MVCC).
4. **Crash recovery.** Instance memory is not persisted across restarts.
5. **Non-transactional updates.** If you modify global state and then roll back the transaction, the modified value may remain for subsequent transactions.
6. **Replay safety.** If a serializability anomaly is detected, SpacetimeDB may re-execute your reducer with the same arguments, causing modifications to global state to occur multiple times.

Reducers are designed to be free of side effects. They should only modify tables. Always store state in tables to ensure correctness and durability.

```rust
// ❌ This will NOT persist across reducer calls
// ❌ Undefined behavior: may or may not persist or correctly update across reducer calls
static mut COUNTER: u64 = 0;

// ✅ Store state in a table instead
Expand All @@ -423,6 +432,132 @@ pub struct Counter {
```
:::

## Scheduling Procedures

Reducers cannot call procedures directly (procedures may have side effects incompatible with transactional execution). Instead, schedule a procedure to run by inserting into a [schedule table](/tables/schedule-tables):

<Tabs groupId="server-language" queryString>
<TabItem value="typescript" label="TypeScript">

```typescript
import { schema, t, table, SenderError } from 'spacetimedb/server';

// Define a schedule table for the procedure
const fetchSchedule = table(
{ name: 'fetch_schedule', scheduled: 'fetch_external_data' },
{
scheduled_id: t.u64().primaryKey().autoInc(),
scheduled_at: t.scheduleAt(),
url: t.string(),
}
);

const spacetimedb = schema(fetchSchedule);

// The procedure to be scheduled
const fetchExternalData = spacetimedb.procedure(
'fetch_external_data',
{ arg: fetchSchedule.rowType },
t.unit(),
(ctx, { arg }) => {
const response = ctx.http.fetch(arg.url);
// Process response...
return {};
}
);

// From a reducer, schedule the procedure by inserting into the schedule table
const queueFetch = spacetimedb.reducer('queue_fetch', { url: t.string() }, (ctx, { url }) => {
ctx.db.fetchSchedule.insert({
scheduled_id: 0n,
scheduled_at: ScheduleAt.interval(0n), // Run immediately
url,
});
});
```

</TabItem>
<TabItem value="csharp" label="C#">

```csharp
#pragma warning disable STDB_UNSTABLE
using SpacetimeDB;

public partial class Module
{
[SpacetimeDB.Table(Name = "FetchSchedule", Scheduled = "FetchExternalData", ScheduledAt = "ScheduledAt")]
public partial struct FetchSchedule
{
[SpacetimeDB.PrimaryKey]
[SpacetimeDB.AutoInc]
public ulong ScheduledId;
public ScheduleAt ScheduledAt;
public string Url;
}

[SpacetimeDB.Procedure]
public static void FetchExternalData(ProcedureContext ctx, FetchSchedule schedule)
{
var result = ctx.Http.Get(schedule.Url);
if (result is Result<HttpResponse, HttpError>.OkR(var response))
{
// Process response...
}
}

// From a reducer, schedule the procedure
[SpacetimeDB.Reducer]
public static void QueueFetch(ReducerContext ctx, string url)
{
ctx.Db.FetchSchedule.Insert(new FetchSchedule
{
ScheduledId = 0,
ScheduledAt = new ScheduleAt.Interval(TimeSpan.Zero),
Url = url,
});
}
}
```

</TabItem>
<TabItem value="rust" label="Rust">

```rust
use spacetimedb::{ScheduleAt, ReducerContext, ProcedureContext, Table};
use std::time::Duration;

#[spacetimedb::table(name = fetch_schedule, scheduled(fetch_external_data))]
pub struct FetchSchedule {
#[primary_key]
#[auto_inc]
scheduled_id: u64,
scheduled_at: ScheduleAt,
url: String,
}

#[spacetimedb::procedure]
fn fetch_external_data(ctx: &mut ProcedureContext, schedule: FetchSchedule) {
if let Ok(response) = ctx.http.get(&schedule.url) {
// Process response...
}
}

// From a reducer, schedule the procedure
#[spacetimedb::reducer]
fn queue_fetch(ctx: &ReducerContext, url: String) {
ctx.db.fetch_schedule().insert(FetchSchedule {
scheduled_id: 0,
scheduled_at: ScheduleAt::Interval(Duration::ZERO.into()),
url,
});
}
```

</TabItem>
</Tabs>

See [Schedule Tables](/tables/schedule-tables) for more scheduling options.

## Next Steps

- Learn about [Tables](/tables) to understand data storage
Expand Down
Loading