Skip to content

spacetime.json config implementation#4199

Open
drogus wants to merge 72 commits intomasterfrom
drogus/spacetime-json
Open

spacetime.json config implementation#4199
drogus wants to merge 72 commits intomasterfrom
drogus/spacetime-json

Conversation

@drogus
Copy link
Collaborator

@drogus drogus commented Feb 4, 2026

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.

bradleyshep and others added 26 commits January 16, 2026 15:42
- Add --client-command flag to specify client dev command
- Add --server-only flag to skip client execution
- Add spacetime.toml config file for project settings
- Auto-detect client command from package.json/Cargo.toml/.csproj
- Save detected command to spacetime.toml for future runs
- Update spacetime init to set default client command
- Add spacetime.toml to all templates with appropriate defaults
- Update documentation
- Add --client-command flag to specify client dev command
- Add --server-only flag to skip client execution
- Add spacetime.toml config file for project settings
- Auto-detect client command from package.json/Cargo.toml/.csproj
- Save detected command to spacetime.toml for future runs
- Update spacetime init to set default client command
- Add spacetime.toml to all templates with appropriate defaults
- Update documentation
- Client environment variables: The dev command now sets SPACETIMEDB_DB_NAME and SPACETIMEDB_HOST environment variables when spawning the client process. This fixes Rust and C# clients which read these env vars to determine which database to connect to. Previously, they would fall back to hardcoded defaults (e.g., quickstart-chat) and fail to connect.

- C# module file watching: The file watcher now correctly handles C# modules which have source files directly in spacetimedb/ rather than in spacetimedb/src/. Previously, watching spacetimedb/src/ would fail with "Input watch path is neither a file nor a directory" for C# projects.
@drogus drogus force-pushed the drogus/spacetime-json branch from 02f4afa to 321629a Compare February 12, 2026 20:28
…ts and overrides

- Replace TypeId/Any type dispatch with serde_json::from_value (fixes u8/num_replicas bug)
- Add --no-config flag to publish, generate, and dev commands
- Error on empty filter match instead of silent fallback to CLI-only mode
- Fix validate() to accept required keys provided via CLI only
- Add parent-to-child field inheritance in PublishConfig
- Fix dev.rs: consolidate triple config loading, fix process::exit, fix unwraps
- Fix include_private to read as bool from config
- Add Language serde::Deserialize with aliases for config file support
- Add unit tests for inheritance, serde deserialization, and validate
- Remove PublishConfig; SpacetimeConfig IS the database entity with
  children, generate, and additional_fields (via serde flatten)
- Add FlatTarget and LoadedConfig for resolved targets and provenance
- Add environment-layered config loading (base > env > local > env.local)
- Add --env flag to publish, generate, and dev commands (dev defaults to "dev")
- Add database-name glob filtering for publish and generate
- Add generate deduplication and generate_entry_specific flag validation
- Rename --module-name to --unreal-module-name (with alias for compat)
- Add --skip-publish and --skip-generate flags to dev
- Add safety prompt in dev when no dev-specific config file is loaded
- Glob filtering: star-matches-all, exact match, multiple wildcards, empty pattern error
- Multi-level env layering: staging with base + env + local + env.local overlay order
- has_dev_file tracking: false for non-dev envs, true for dev env
- dev not propagated to children in FlatTarget fields
- Generate dedup with inherited generate from parent (same module-path)
- Generate glob filtering and no-match error
- iter_all_targets and count_targets
- determine_publish_configs: no config, CLI database, config targets, config without database
- CLI flag verification: --env default, --skip-publish, --skip-generate
"generate": "cargo run -p gen-bindings -- --replacement ../../../src/index && prettier --write src/module_bindings",
"spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server",
"spacetime:start": "spacetime start",
"spacetime:start": "spacetime start server",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"spacetime:start": "spacetime start server",
"spacetime:start": "spacetime start",

"generate": "cargo run -p gen-bindings -- --replacement ../../../src/index && prettier --write src/module_bindings",
"spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --project-path server",
"spacetime:generate": "spacetime generate --lang typescript --out-dir src/module_bindings --module-path server",
"spacetime:start": "spacetime start server",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
"spacetime:start": "spacetime start server",
"spacetime:start": "spacetime start",

/// Find and load config with environment layering from the current directory.
///
/// Loading order (each overlays the previous via top-level key replacement):
/// 1. `spacetime.json` (required)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm is this really required? If so, should it be?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why there are formatting changes in these. I presume somehow I formatted these and they're not in the above workspace. Should I revert these?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants