surrealkit.toml declares what a SurrealKit project contains. Template variables and type generation settings have always lived here. Since 1.0 the file also declares schema modules and database targets, which makes its location worth knowing rather than incidental.
Every section is optional. A project with no config file, or one holding only [variables] and [typegen], behaves the way it did before 1.0: one unnamed schema module applied to one database taken from the environment.
Where SurrealKit looks for it
surrealkit init writes surrealkit.toml to the current directory, next to database/ rather than inside it:
surrealkit.toml # project configuration
database/
├── schema/
├── rollouts/
├── snapshots/
├── seed/
├── tests/
└── setup.surqlSurrealKit starts at the working directory and walks up to the filesystem root, taking the first surrealkit.toml it finds. Running a command from apps/api/ in a monorepo therefore finds the config at the repository root. Before 1.0 the file was read from the working directory only.
There is no flag for pointing at a different file. To use another config, change directory first.
The upward walk applies to [schema.*] and [target.*] only. [variables] and [typegen] are still read from the working directory alone, so running from a subdirectory applies your modules but silently drops your template variables and stops generating TypeScript. Run project commands from the directory that holds surrealkit.toml until this is resolved.
Inside a container
The published image is built on gcr.io/distroless/cc-debian12:nonroot and sets no working directory of its own, so a container inherits /home/nonroot from the base image. Config discovery starts there, which means a mounted surrealkit.toml has to land at /home/nonroot/surrealkit.toml:
docker run --rm \
-v "$(pwd)/database:/database:ro" \
-v "$(pwd)/surrealkit.toml:/home/nonroot/surrealkit.toml:ro" \
ghcr.io/surrealdb/surrealkit:1.0.0-beta.1 \
--host wss://production-6xk2.aws-euw1.surreal.cloud \
--ns main --db main --user root --pass secret syncSetting a working directory is the alternative, and lets you mount the project once at its own shape:
docker run --rm -w /project \
-v "$(pwd):/project" \
ghcr.io/surrealdb/surrealkit:1.0.0-beta.1 \
--host wss://production-6xk2.aws-euw1.surreal.cloud \
--ns main --db main --user root --pass secret --folder /project/database syncThe schema mount target is /database in the first example because the image sets SURREALDB_FOLDER=/database. Point --folder somewhere else, as the second example does, and that default no longer applies. Get the endpoint for a Cloud instance with surrealctl instance endpoint.
A read-only mount suits sync against an existing project. It conflicts with [typegen] typescript, which writes into the mounted tree, and with the setup.surql that sync scaffolds when the file is absent. Drop :ro for either.
Sections
| Section | Purpose |
|---|---|
[variables] | Default values for template variables |
[typegen] | Type generation output directory and formatter |
[schema.<name>] | A named schema module |
[target.<name>] | A named database target |
Unknown keys and unknown sections are rejected when the file is parsed, so a misspelt key fails the command rather than being ignored.
[variables]
A free-form map of template variable names to values. Keys are matched case-insensitively, so schema_prefix and SCHEMA_PREFIX set the same variable. This is the lowest-priority source: --var and SURREALKIT_VAR_* both outrank it.
[variables]
schema_prefix = "myapp"
environment = "development" [typegen]
[typegen]
typescript = "src/types"
format = "biome check --write" [schema.<name>]
Available since: v1.0
Declares one schema module. The section name is the module name.
Module names are lowercase a-z, 0-9, _ and -, must start with a letter or a digit, and are at most 64 characters. meta is reserved. The charset is narrow because the name appears in metadata partition keys, lock keys, and as a directory name.
[schema.core]
[schema.billing]
depends_on = ["core"] [target.<name>]
Available since: v1.0
Declares one database to apply modules to. Every field is optional and falls back to the ambient connection, so a target usually names only its namespace and database.
[target.acme]
ns = "acme"
db = "prod"
pass_env = "ACME_DB_PASSWORD"
primary = true
[target.warehouse]
ns = "internal"
db = "analytics"
schemas = ["core", "analytics"]
pass_env = "WAREHOUSE_DB_PASSWORD"Passwords
A pass or password key under [target.*] is rejected. SurrealKit scans for it before parsing the rest of the file, so the error names the fix and lists every offending target at once:
passwords must not be committed to source control, but surrealkit.toml sets them inline:
[target.acme] pass
[target.globex] password
Use environment indirection instead:
pass_env = "MY_DB_PASSWORD"The offending value is never echoed. Name an environment variable with pass_env instead, and set it wherever the command runs. A pass_env that names an unset variable fails before any connection is opened, so a misconfigured target cannot leave a fan-out half applied.
Validation
The whole file is validated before a database connection is attempted, so a mistake costs a failed command rather than a partial write:
Module names must satisfy the charset and length rules above, and must not be
meta.A
depends_onentry must name a declared module, and a module cannot depend on itself.Dependency cycles are rejected, with the cycle named in the error.
A
schemasentry under[target.*]must name a declared module.At most one target may set
primary = true.Any unknown key or section is a parse error.
A complete file
[variables]
app_name = "acme"
[typegen]
typescript = "src/types"
format = "biome check --write"
[schema.core]
# path defaults to database/modules/core/schema
[schema.billing]
depends_on = ["core"]
[target.acme]
ns = "acme"
db = "prod"
pass_env = "ACME_DB_PASSWORD"
primary = true
[target.globex]
ns = "globex"
db = "prod"
pass_env = "GLOBEX_DB_PASSWORD"Next steps
Schema modules and targets: apply several schemas across several databases
Template variables: parameterise schema files per environment
Type generation: emit JSON and TypeScript from a live database