SpacetimeDB 2.0 is almost here! 🌟
Today we're announcing SpacetimeDB 2.0 as a preview release. SpacetimeDB 2.0 has some big changes, so buckle up!
TypeScript/JavaScript Support
In October we launched beta support for TypeScript and JavaScript, and we're happy to announce that with the release of 2.0 TypeScript support is leaving beta! We also have a bunch of updates to the API that being much needed consistency to the APIs.
Web framework integration
Along with TypeScript and JavaScript support, we've built integrations and templates with all your favorite frameworks including:
- Angular
- React
- Nuxt
- Vue
- Next.js
- Node
- Deno
- TanStack
- Remix
- Svelte
- Bun
Unreal Engine/C++ Support
For all those who have been waiting for official Unreal Engine 5 support, it's here! Alongside C++ modules as well!
Incredible performance
SpacetimeDB 2.0 delivers eye watering throughput even for tiny transactions with high contention. Well over 100k transactions per second for TypeScript modules and up to 170k transactions per second for Rust modules!
A new Maincloud FREE tier and all new pricing!
With 2.0, we're also announcing a brand new, simpler pricing scheme along with a free tier for users who want to try out Maincloud!
This new simplified pricing makes it easier than ever to predict your costs. Check out our pricing calculator on the pricing page.
Spacerace Referral Program
Alongside our new pricing, we're introducing the Spacerace Referral Program where you can get up to 400x more free credits per month by referring friends to the platform.
Procedures and HTTP calls
With 2.0 your SpacetimeDB modules are getting a big boost in capability too. For the first time, your modules can now access the outside world with Procedure Functions. Procedure functions give you the ability to make HTTP calls from within your module, letting you integrate directly with external APIs. This is how easy it is to call ChatGPT's API from within your module:
export const ask_ai = spacetimedb.procedure(
{ prompt: t.string(), apiKey: t.string() },
t.string(),
(ctx, { prompt, apiKey }) => {
// Make the HTTP request to OpenAI
const response = ctx.http.fetch('https://api.openai.com/v1/chat/completions', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${apiKey}`,
},
body: JSON.stringify({
model: 'gpt-4',
messages: [{ role: 'user', content: prompt }],
}),
// Give it some time to think
timeout: TimeDuration.fromMillis(3000),
});
if (response.status !== 200) {
throw new SenderError(`API returned status ${response.status}`);
}
const data = response.json();
const aiResponse = data.choices?.[0]?.message?.content;
if (!aiResponse) {
throw new SenderError('Failed to parse AI response');
}
// Store the conversation in the database
ctx.withTx(txCtx => {
txCtx.db.aiMessage.insert({
user: txCtx.sender,
prompt,
response: aiResponse,
createdAt: txCtx.timestamp,
});
});
return aiResponse;
}SpacetimeAuth (and Clerk and Auth0)
And to help you avoid needing to set up additional sidecars and services alongside SpacetimeDB we've also introduced SpacetimeAuth, our first party auth solution. SpacetimeAuth is completely free to use with SpacetimeDB Maincloud!
We've also built tutorials for how to integrate with other auth providers like Clerk and Auth0!
View Functions
In SpacetimeDB 2.0, adding sophisticated read permissions to expose portions of your data to users is as simple as creating a function:
export const players_for_level = spacetimedb.anonymousView(
{ name: 'players_for_level', public: true },
t.array(playerAndLevelRow),
(ctx) => {
const out: Array<{ id: bigint; name: string; level: bigint }> = [];
for (const playerLevel of ctx.db.playerLevels.level.filter(2n)) {
const p = ctx.db.players.id.find(playerLevel.player_id);
if (p) out.push({ id: p.id, name: p.name, level: playerLevel.level });
}
return out;
}
);You can think of view functions as a table that is backed by a reducer. From the client, they look just like any other table in your database, but in the module they're represented as a function that returns rows that you want to expose to clients. Better yet, the table is automatically parameterized by the identity of the viewing client, allowing different clients to see different data when viewing the same table.
Views can also return custom types allowing you to not only filter rows, but also columns. Views are an elegant way of solving read permissions without introducing a single new concept!
Typed Query Builder
In SpacetimeDB 2.0, you can kiss your stringly-typed queries goodbye! With our 2.0 SDK and code generation, we generate beautifully typed query builder APIs that allows your clients to build arbitrary queries over the data.
ctx.subscriptionBuilder().subscribe([tables.user.where(user => user.name.eq("Tyler")), tables.message]);Never worry about runtime errors with your queries again! And the strongly typed queries also help LLMs succeed more often as well.
Even better, you can access this same query builder API inside your view functions to return queries from your views so they can be optimized by our incremental evaluation query engine!
export const high_scorers = spacetimedb.anonymousView(
{ name: 'high_scorers', public: true },
t.array(players.rowType),
(ctx) => {
return ctx.from.players
.where(p => p.score.gte(1000n))
.where(p => p.name.ne('BOT'));
}
);Event Tables
Event tables are also all new in SpacetimeDB 2.0. Event tables allow you to publish short lived event information to clients without needing to clean up your tables later on. Event tables act like regular tables, but the rows are automatically deleted by SpacetimeDB at the end of a transaction. This both saves you storage costs and also bandwidth, as the database needs to synchronize less state!
Publishing an event to clients is as simple as inserting into a row into the event table, and subscribing to it like any other table.
// server
const damageEvent = table({
public: true,
event: true,
}, {
entity_id: t.identity(),
damage: t.u32(),
source: t.string(),
});
export const attack = spacetimedb.reducer(
{ target_id: t.identity(), damage: t.u32() },
(ctx, { target_id, damage }) => {
// Game logic...
// Publish the event
ctx.db.damageEvent.insert({
entity_id: target_id,
damage,
source: "melee_attack",
});
}
);
// client
conn.db.damageEvent.onInsert((ctx, event) => {
console.log(`Entity ${event.entityId} took ${event.damage} damage from ${event.source}`);
});spacetime.json configuration
With 2.0, we're also introducing a new config file to make it easier to interact with your databases. Now with spacetime.json you can save all your database configuration in a single file that you check in to git, so instead of this:
spacetime generate --lang typescript --out-dir src/module_bindings
spacetime publish --server maincloud --module-path spacetimedb my-databaseYou can now just type this:
spacetime generate
spacetime publishspacetime dev
Development is getting simpler too, with our new spacetime dev command. This command is your one stop shop for development. It:
- Watches for changes in your module code
- Compiles your module
- Generates your client module bindings
- Publishes your module
- Runs your client
Now all you have to do is change your code and your whole app updates instantly!
All new dashboard and metrics
We've also added beautiful new dashboards and analytics so you can monitor your apps and data in real-time! And they update in real-time too! It's incredible to see tables updating live, trust us!
Better LLM tools and benchmarks
SpacetimeDB is now also optimized for LLMs as well, both to help you understand SpacetimeDB and also to help you write your SpacetimeDB apps. New projects automatically ship with the appropriate AGENT.md files to help you get started immediately.
Project collaborators and organizations
For groups and teams, we've not introduced project collaborators and organizations. With project collaborators you can invite your friends and colleagues to build and publish modules with you.
Larger organizations can sign up for our Maincloud Team tier to reserve their team name and get advanced features for permissions management.
Postgres Wire Protocol Compatibility
If you've got existing tools that work with Postgres, they might work with SpacetimeDB now too! SpacetimeDB 2.0 supports the Postgres Wire Protocol, meaning you can use psql and other Postgres tools to query SpacetimeDB directly.
SpacetimeDB does not yet support the full suite of Postgres features, but this is the beginning of a long effort to make SpacetimeDB fully Postgres compatible.
Much much more
Over the past several months we've merged literally hundreds of bug fixes, UX improvements, and performance improvements. If you haven't tried SpacetimeDB out, now is an excellent time to try!
What's Changed
- Rework
JobCoresin order to core-pin v8 instance threads by @coolreader18 in #4128 - Fix for
cargo ci dllsmissing some.metafiles by @rekhoff in #4178 - [TS] Implement de/serialization as a tree of closures by @coolreader18 in #3957
- Add context about maincloud publishing being free of charge by @aasoni in #4174
- implement TryFrom for V10 by @Shubham8287 in #4190
- Reorganize TS sdk by @coolreader18 in #3915
write-nuget-config.shresolves paths properly by @bfops in #4193- gitignore - properly ignore nuget config files by @bfops in #4192
- Update 00250-zen-of-spacetimedb.md by @cloutiertyler in #4145
- Update README.md by @cloutiertyler in #4119
- Bump esm (gzip) size limit by @jdetter in #4198
- Update
librusty_v8.nixfor our new V8 dependency version. by @gefjon in #4202 - Identifiers: Refactor + Improve type-safety & performance by @Centril in #4177
- Translate smoketests from Python to Rust by @cloutiertyler in #4102
- Pass Reducer/ProcedureContext by reference by @Centril in #4203
RawModuleDefV10Scheduled functions should not be callable by @Shubham8287 in #4179- CI - csharp-testsuite v8 dance done properly by @bfops in #4209
- add missing TypeScript language for 'Module can be written in' by @ExpLuuk in #4205
- [TS] Introduce v2 JS abi, with memory allocated by the caller by @coolreader18 in #4186
- [2.0 Breaking]: Remove sender field from [Reducer|View|Procedure]Context by @joshua-spacetime in #4208
- Smoketests - Collapse one directory level by @bfops in #4184
- Moved C# SDK's
packagesignore from SDK's.gitignoreto project root by @rekhoff in #4211 - [TS] Module-side performance improvements by @coolreader18 in #4187
- CI - Merge
xtask-smoketestintocargo ci smoketestsby @bfops in #4185 - [2.0 Breaking] Make
connection_ida method onReducerContextby @joshua-spacetime in #4215 - [TS] Make ProcedureCtx a class by @coolreader18 in #4210
- Bump Rust to 1.93.0 by @coolreader18 in #4180
- CI - Fix v8 in debug and release by @bfops in #4223
- Add C++ Bindings by @JasonAtClockwork in #3544
- [2.0 Breaking] Expose
RawModuleDefV10from WASM modules by @joshua-spacetime in #4216 - core: Add context about which database got a durability panic by @kim in #4221
- CI - Fix cargo-related errors by @bfops in #4242
- cli: Avoid empty error message by @kim in #4230
- Add index benchmarks for composites of primitives by @Centril in #4248
- Docs Update for C++ [1/4] by @JasonAtClockwork in #4118
- Docs Update for C++ [3/4] by @JasonAtClockwork in #4163
- Add code owners for CI stuff by @bfops in #4245
- Docs Update for C++ [4/4] (Blackholio) by @JasonAtClockwork in #4169
- Docs Update for C++ [2/4] by @JasonAtClockwork in #4129
- [C#] Module bindings for Typed Query Builder by @rekhoff in #4159
- RawModuleDefV10 from V8 modules. by @Shubham8287 in #4194
- Block procedures from requesting private ip ranges by @joshua-spacetime in #4243
- Remove
__decribe_module_v10__by @Shubham8287 in #4246 - feat: Quickstart and client for Plain JS Script Tags by @clockwork-tien in #4161
- Reorganize types generated for typescript clients by @joshua-spacetime in #4258
- [TS] Bundle ICU data by @coolreader18 in #4253
- Quickstart bun by @bradleyshep in #4154
- Fix release for GLIBC_2.38 issue by @jdetter in #4268
- Quickstart nodejs by @bradleyshep in #4112
- Quickstart nextjs by @bradleyshep in #4097
- LLM Oneshot Prompts, Oneshotted Apps, and Cursor Rules (C#/Rust/TS) by @bradleyshep in #4032
- Added C++ smoketest for quickstart-chat + updated chat doc by @JasonAtClockwork in #4109
- Quickstart remix by @bradleyshep in #4113
- Add warning prompt for 1.0 -> 2.0 module upgrade path by @joshua-spacetime in #4247
- Fix docker unauthenticated pull rate limit issue in CI by @jdetter in #4272
- [2.0 Breaking] Add --include-private and default private tables to not generate by @JasonAtClockwork in #4241
- Keynote Spacetime simulation comparisons by @bradleyshep in #4072
- feat: Quickstart and client for Nuxt by @clockwork-tien in #4176
- Deno quickstart by @bradleyshep in #4191
- [TS] Export reducers, etc from a module by @coolreader18 in #4220
- TypeScript modules: Expose hash indices by @Centril in #4233
- Rename
with_module_name->with_database_nameby @gefjon in #4267 - Download from Digital Ocean if Github download fails by @jdetter in #4265
- Add missing query builder docs by @joshua-spacetime in #4196
- [TS] Throw error objects from syscalls by @coolreader18 in #4260
- Bump rolldown to 1.0.0-rc.3 by @coolreader18 in #4259
- client-api: Resolve organization names via the tld, not the dns table by @kim in #4266
- feat: Quickstart and client for TanStack Start by @clockwork-tien in #4107
- Version upgrade to 2.0 by @jdetter in #4252
- websocket format: use
RawIdentifierby @Centril in #4181 - CI - Fix smoketests using wrong binary path by @bfops in #4280
- Expand and correct docs on
procedure_http_requestABI function by @gefjon in #3950 - Sort version output of
spacetime version listby @aasoni in #4250 - Implement server-side support for the v2 websocket protocol by @cloutiertyler in #4213
- [TS] Remove fast-text-encoding polyfill by @coolreader18 in #4283
- Typescript v2 API by @jsdt in #4271
- Limit update() to only work on primary keys by @cloutiertyler in #4279
- Update Rust client SDK for V2 WebSocket format by @gefjon in #4257
- [TS] Pretty-print objects passed to console.log by @coolreader18 in #4285
- [V8 host] Fix panic when client disconnects by @coolreader18 in #4286
- Event tables: datastore tests, migration validation, and bootstrap fix by @cloutiertyler in #4251
- Standardize query builder syntax across Rust, TypeScript, and C# (Server/Client) by @cloutiertyler in #4261
- [C#] Adding RawModuleDefV10 to C# Module Bindings by @rekhoff in #4288
- [TS] schema() takes an object by @coolreader18 in #4273
- Append commit instead of individual transactions to commitlog by @kim in #4140
- Revert "Append commit instead of individual transactions to commitlog (#4140)" by @clockwork-labs-bot in #4292
- Fix Unreal Blackholio Tutorial for project rename by @JasonAtClockwork in #4044
- Set name of network thread in C# SDK by @SteveGibsonCL in #4090
- [2.0 Breaking] Update C# client SDK for V2 WebSocket format by @clockwork-labs-bot in #4293
- Add
ws_schema.jsonto gitignore by @gefjon in #2745 - CI - Check smoketests for changes by @bfops in #4282
- Add GREMLINS.md documenting repo bots and agents by @clockwork-labs-bot in #4290
- Case conversion Raw Def changes by @Shubham8287 in #4294
- Implement event tables (server, Rust/TS/C# codegen + client SDKs) by @cloutiertyler in #4217
spacetime.jsonconfig implementation by @drogus in #4199- Add Angular integration by @JulienLavocat in #4139
- Rust: macro change
name->accessorby @Shubham8287 in #4264 - TS Quickstart: Store different auth tokens for different servers/modules by @jsdt in #3252
- Trigger view refresh when a WASM procedure commits a transaction by @joshua-spacetime in #4301
- Don't call init reducer in spacetime generate by @coolreader18 in #4312
- Fix metadata version check for 2.0 by @bfops in #4313
- Updated C#
Nameattribute toAccessorby @rekhoff in #4306 - docs: expand Maincloud deployment page by @clockwork-labs-bot in #4316
- Docs: Expand FAQ for 2.0 launch by @clockwork-labs-bot in #4314
- SQL alias by @Shubham8287 in #4304
- Trigger view refresh when a V8 procedure commits a transaction by @joshua-spacetime in #4302
- [TS] Fix ArrayBuilder.{name,default} by @coolreader18 in #4321
- Minor fixes to examples in event tables document by @gefjon in #4322
- Add
accessor_namefield inModuleDefby @Shubham8287 in #4323 - Improve
spacetime buildfor typescript by @coolreader18 in #4330 - Pinning C++ and Unreal to 1.12.0 by @JasonAtClockwork in #4328
- [TS] better build followup by @coolreader18 in #4334
- Fix hash index round-trip through st_indexes by @clockwork-labs-bot in #4336
- [Docs] Revisions to Chat App doc for 2.0 release by @rekhoff in #4335
- Add migration-focused diagnostics to Rust table macro by @gefjon in #4342
- Small fixes for the Blackholio tutorial by @JasonAtClockwork in #4343
- Fix query optimization for semijoins by @joshua-spacetime in #4287
- Fix CI error stemming from
cargo updateby @coolreader18 in #4341 spacetime.jsonrelated fixes and improvements by @drogus in #4332- Rust docs updated for
nametoaccessorby @JasonAtClockwork in #4344 - Return ModuleInfo from check_module_validity by @coolreader18 in #4339
- [C#] Spacetime 2.0 Query Builder behavior validation by @rekhoff in #4333
- Fixes for procedure example in docs by @coolreader18 in #4346
- Docs - add shared C++ version notice inside first C++ tab across docs by @JasonAtClockwork in #4348
- Add smoketests for template generation by @drogus in #4000
- Add more tests for typescript client and fix some bugs by @jsdt in #4307
- Update subscription and query builder docs by @joshua-spacetime in #4329
- [TS] Improve autogen autocompletion and typing by @coolreader18 in #4309
- Add ConnectionManager for robust React lifecycle handling by @douglance in #4028
- Update to generated C# template package version by @rekhoff in #4349
- Fix publishing and generating from subdirs if config is present by @drogus in #4351
- Remove database names in quickstarts by @jdetter in #4354
- Fix warnings in regen-cpp-moduledef by @coolreader18 in #4355
- Update benchmark docs by @jdetter in #4345
- Warn about publishing DBs from non-local/non-dev spacetime.json in dev by @drogus in #4350
- Fix
spacetime devwatch filtering and improve quickstart copy-paste experience by @cloutiertyler in #4317 - [TS] Improve how exceptions get rendered in messages by @coolreader18 in #4347
- Make Rust test clients listen for reducer errors by @gefjon in #4359
- Fix template
global.jsonunder Windows by @bfops in #4357 - Add more debug logging to the typescript client by @jsdt in #4356
- gitignore AI agent config dirs by @bfops in #4365
- [C#] Cononical Names and Casing Settings in ModuleDef by @rekhoff in #4368
- Case conversion by @Shubham8287 in #4263
- Fix various TS templates by @bradleyshep in #4360
- Add #[spacetimedb::settings] for module-level configuration by @clockwork-labs-bot in #4366
- Allow skipping DB if the config file is available by @drogus in #4358
- typescript: canonical naming for reducer and procedure. by @Shubham8287 in #4371
- Change deno quickstart to use package.json instead of deno.json by @bradleyshep in #4374
- Don't shadow Math.random() in typescript by @coolreader18 in #4375
New Contributors
Full Changelog: v1.12.0-hotfix1...v2.0.0-rc1