Skip to content

SurrealKit

Configuration

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, so it now matters where the file is.

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.

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.surql

SurrealKit 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.

Warning

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.

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-rc.1 \
  --host wss://production-6xk2.aws-euw1.surreal.cloud \
  --ns main --db main --user root --pass secret sync

Setting 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-rc.1 \
  --host wss://production-6xk2.aws-euw1.surreal.cloud \
  --ns main --db main --user root --pass secret --folder /project/database sync

The 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 surreal cloud instance endpoint.

Note

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.

SectionPurpose
[variables]Default values for template variables
[typegen]Type generation outputs, formatter and strictness
[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.

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"

Keys

NameTypeDefaultDescription
typescript
pathNoneWhere generated TypeScript goes. Setting it enables TypeScript output for typegen and sync. A path ending in .ts, .mts or .cts is the file itself; any other path is a directory.
filename
stringindex.tsThe file to write inside the typescript directory. Not used when typescript names a file.
format
stringNoneFormatter run on the generated file. The file path is appended to the command as its last argument. Failures are warnings unless strict is set.
json
pathNoneWhere the JSON schema document goes. Setting it makes sync write the document too. A path ending in .json is the file itself; any other path is a directory, and the file in it is schema.json.
strict
booleanfalseFail instead of warning when an output cannot be produced exactly as configured: a failing formatter, a field type typegen cannot parse, and in sync, any typegen failure after the schema was applied.
generated_at
booleantrueWhether the JSON carries a generatedAt timestamp. Set it to false so the same schema always produces the same bytes.
schema_version
integer1Which JSON document to write: 1, or 2 for schema document v2. The TypeScript output is the same either way.

Unknown keys in [typegen] are an error, so a misspelt key cannot turn an output off without a message. The section also takes engine, experimental, acknowledge and [typegen.emit.<name>] for surrealkit compile and external emitters, which Type generation introduces.

[typegen]
typescript = "src/types"
format = "biome check --write"

Declares one schema module. The section name is the module name.

Keys

NameTypeDefaultDescription
path
path<folder>/modules/<name>/schemaWhere this module's .surql files live. A relative path resolves against the project folder; an absolute path is used as given.
depends_on
string[][]Modules that must be applied before this one. Selecting a module also selects everything it depends on.

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"]

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.

Keys

NameTypeDefaultDescription
host
stringNoneDatabase endpoint URL. Inherits --host when unset.
ns
stringNoneNamespace. Inherits --ns when unset.
db
stringNoneDatabase name. Inherits --db when unset.
user
stringNoneUsername. Inherits --user when unset.
pass_env
stringNoneName of an environment variable holding this target's password. Passwords are never read from the config file itself.
auth_level
stringNoneOne of root, namespace (or ns), database (or db), and none (also spelled no-auth or noauth).
schemas
string[]NoneRestrict which modules apply to this target. All declared modules apply when unset.
primary
booleanNoneUse this target when neither --target nor --all is given. Defaults to false, and at most one target may set it.
connect_timeout_secs
integer30Time limit for connecting and signing in. 0 waits indefinitely.
query_timeout_secs
integerNoneTime limit for the SQL of one rollout step. Unset means no limit.

A value set in a target wins over the equivalent CLI flag and environment variable, for every key. Naming a target selects the connection it describes, so --host does not override a target's host, and --connect-timeout-secs 5 --target warehouse uses the target's connect_timeout_secs when it sets one. A key the target leaves out is inherited in the usual order: CLI flag, then environment variable, then .env, then the default.

[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"

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:

Error output
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.

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_on entry must name a declared module, and a module cannot depend on itself.

  • Dependency cycles are rejected, with the cycle named in the error.

  • A schemas entry under [target.*] must name a declared module.

  • At most one target may set primary = true.

  • Any unknown key or section is a parse error.

surrealkit.toml
[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"

Was this page helpful?