Configuration File (spawn.toml)
The spawn.toml file configures your Spawn project, defining database connections and project structure.
File location
Section titled “File location”By default, Spawn looks for spawn.toml in the current directory. Override with --config-file:
spawn --config-file /path/to/config.toml migration applyTop-level fields
Section titled “Top-level fields”spawn_folder
Section titled “spawn_folder”Type: String
Required: Yes
Path to the directory containing migrations, components, tests, and pinned snapshots.
spawn_folder = "./database/spawn"This would expect the following directory layout:
./database/spawn/migrations/./database/spawn/components/./database/spawn/tests/./database/spawn/pinned/
template_up
Section titled “template_up”Type: String
Required: No
Default: None (uses the built-in default template)
Path to a custom template file used by spawn migration new instead of the built-in default. Resolved relative to spawn_folder.
template_up = "templates/custom-up.sql"With this set, spawn migration new copies the contents of spawn_folder/templates/custom-up.sql into the new migration’s up.sql instead of the built-in default:
BEGIN;
COMMIT;template_test
Section titled “template_test”Type: String
Required: No
Default: None (uses the built-in default template)
Path to a custom template file used by spawn test new instead of the built-in default. Resolved relative to spawn_folder.
template_test = "templates/custom-test.sql"With this set, spawn test new copies the contents of spawn_folder/templates/custom-test.sql into the new test’s test.sql instead of the built-in default:
-- Test fileSELECT 1;target
Section titled “target”Type: String
Required: No
Default: None
The default target to use for commands. Must match a key in [targets].
target = "local"Override per-command with --target:
spawn --target production migration statusenvironment
Section titled “environment”Type: String
Required: No
Default: None
Global environment override. Overrides the environment field in target configs.
environment = "dev"This is rarely set at the top level. Usually each target defines its own environment.
project_id
Section titled “project_id”Type: String (UUID)
Required: No
Default: Auto-generated on spawn init
Unique and anonymous identifier for telemetry. Generated automatically by spawn init.
project_id = "a1b2c3d4-e5f6-7890-abcd-ef1234567890"telemetry
Section titled “telemetry”Type: Boolean
Required: No
Default: true
Whether to send anonymous usage telemetry.
telemetry = falseSet the DO_NOT_TRACK environment variable to disable telemetry globally.
secrets
Section titled “secrets”Type: Table
Required: No
Named secrets available to templates via the secret() function. See Secrets below for the field format, and the Secrets guide for how they’re used in templates and which commands reveal vs. mask them.
Target configurations
Section titled “Target configurations”The [targets] section defines one or more database connections. Each target is a table with the following fields. For practical setup examples including Docker and Google Cloud SQL, see the Database Connections guide.
engine
Section titled “engine”Type: String
Required: Yes
Values: "postgres-psql"
The database engine type. Currently only PostgreSQL via psql is supported.
[targets.local]engine = "postgres-psql"spawn_database
Section titled “spawn_database”Type: String
Required: No
The database name where Spawn stores migration tracking tables (in the spawn_schema). If not provided, defaults to using the same database that your connection command uses. This database must already exist.
spawn_database = "spawn"spawn_schema
Section titled “spawn_schema”Type: String
Required: No
Default: "_spawn"
The schema where Spawn creates its internal tracking tables (migration_history, etc.). This schema will be created if it does not yet exist.
spawn_schema = "_spawn"environment
Section titled “environment”Type: String
Required: No
Default: "prod"
Environment identifier. Available in migration templates as {{ env }}. Used for conditional logic:
{% if env == "dev" %}INSERT INTO test_data VALUES ('sample');{% endif %}Common values: "dev", "staging", "prod"
environment = "dev"command
Section titled “command”Type: Table (CommandSpec)
Required: Yes
Specifies how to execute SQL against the target. Two modes: direct and provider. For now, only connection via PostgreSQL psql is supported, so this should be the command that allows piping changes to the database. See the Database Connections guide for detailed examples of both modes.
Direct command
Section titled “Direct command”Use when you have a straightforward way to invoke psql.
command = { kind = "direct", direct = ["psql", "-U", "postgres", "mydb"] }Docker example:
command = { kind = "direct", direct = [ "docker", "exec", "-i", "mydb-container", "psql", "-U", "postgres", "mydb"] }Provider command
Section titled “Provider command”Use when the connection details need to be resolved dynamically, or are faster to resolve once per command for faster performance (e.g., via gcloud).
The provider command must output the command as a shell command.
Spawn runs the provider command, parses the command, then executes the resolved command with append args added.
Google Cloud SQL example:
command = { kind = "provider", provider = [ "gcloud", "compute", "ssh", "db-instance", "--zone", "us-central1-a", "--project", "my-project", "--dry-run" ], append = ["-T", "sudo", "-u", "postgres", "psql", "mydb"]}The --dry-run flag makes gcloud output the SSH command as a string instead of executing it.
Secrets
Section titled “Secrets”The [secrets] table defines values that templates can read via the secret() function, so passwords and other sensitive values don’t need to be committed as plain template variables. See the Secrets guide for how secrets are used in templates and which commands reveal vs. mask them; this section covers the spawn.toml field format.
Each secret has a default source and optional per-environment overrides, keyed by the same environment names used by [targets.*].environment.
[secrets.application_password.default]source = "host_file"path = "/run/secrets/application-password"
[secrets.application_password.environments.dev]source = "file"path = "./local-secrets/application-password.txt"When a template calls secret("application_password"), Spawn looks up environments.<current environment> first, falling back to default if there’s no override for the current environment. default is required — there’s no implicit “no secret configured” fallback.
Sources
Section titled “Sources”Reads an OS environment variable.
[secrets.application_password.default]source = "env"name = "APPLICATION_PASSWORD"Reads a file via spawn’s configured operator, with any trailing newline stripped — resolved the same way any other file spawn reads is (read_file, migration/component lookups, etc.). It is not a real filesystem path, so an absolute path here will not reach a real host location — use host_file for that.
[secrets.application_password.environments.dev]source = "file"path = "./local-secrets/application-password.txt"host_file
Section titled “host_file”Reads a file directly from the host filesystem, bypassing the operator, with any trailing newline stripped. Use this for secrets mounted on the host outside spawn’s storage — Docker/Kubernetes secrets under /run/secrets, systemd’s LoadCredential=, or an already-decrypted sops/gpg output file.
[secrets.application_password.default]source = "host_file"path = "/run/secrets/application-password"command
Section titled “command”Runs a command and uses its trimmed stdout as the value. Useful for secret managers with a CLI (Vault, 1Password, sops, systemd-creds, etc.).
[secrets.application_password.default]source = "command"command = ["op", "read", "op://vault/application-password/password"]literal
Section titled “literal”An inline value. Requires insecure = true — Spawn refuses to use a literal secret without it, so a plaintext value committed to spawn.toml can’t accidentally become a project’s “secure default”. This is enforced whenever the secret is resolved (including a masked migration build), not just when it’s actually displayed. Intended for local development only.
[secrets.application_password.environments.dev]source = "literal"value = "dev-only-password"insecure = trueSee Secrets: Masking for which commands reveal real values vs. mask them.
Complete example
Section titled “Complete example”spawn_folder = "./database/spawn"target = "local"project_id = <replace with random uuid>
[targets.local]spawn_database = "spawn"spawn_schema = "_spawn"environment = "dev"engine = "postgres-psql"command = { kind = "direct", direct = ["docker", "exec", "-i", "mydb", "psql", "-U", "postgres", "postgres"]}
[targets.staging]spawn_database = "spawn"spawn_schema = "_spawn"engine = "postgres-psql"environment = "prod"command = { kind = "provider", provider = [ "gcloud", "compute", "ssh", "staging-db", "--zone", "us-central1-a", "--project", "my-project-staging", "--dry-run" ], append = ["-T", "sudo", "-u", "postgres", "psql", "mydb"]}
[targets.production]spawn_database = "spawn"spawn_schema = "_spawn"engine = "postgres-psql"environment = "prod"command = { kind = "provider", provider = [ "gcloud", "compute", "ssh", "prod-db", "--zone", "us-east1-b", "--project", "my-project-prod", "--dry-run" ], append = ["-T", "sudo", "-u", "postgres", "psql", "mydb"]}Environment variable overrides
Section titled “Environment variable overrides”Spawn supports environment variable overrides with the SPAWN_ prefix:
export SPAWN_TARGET=productionspawn migration statusThis is equivalent to spawn --target production migration status.