Migrations
Talos includes built-in database migrations. Run them before first use and after each upgrade.
Commands
# Apply all pending migrations
talos migrate up --database "sqlite:///var/lib/talos/data.db"
# Roll back the last migration (--steps defaults to 1)
talos migrate down --database "sqlite:///var/lib/talos/data.db"
# Roll back the last three migrations
talos migrate down --steps 3 --database "sqlite:///var/lib/talos/data.db"
# Check migration status
talos migrate status --database "sqlite:///var/lib/talos/data.db"
# Force a specific version after a partial migration left the schema dirty
talos migrate force 17 --database "sqlite:///var/lib/talos/data.db"
Upgrade workflow
- Back up the database. For PostgreSQL or CockroachDB, take a logical backup with
pg_dumporBACKUP INTO; for MySQL, usemysqldump. SQLite users can simply copy the file. - Drain admin traffic. Run
talos migrate upfrom a single instance — concurrent migration runners race against each other and can leave the schema dirty. - Apply migrations. Run
talos migrate up. Watch stderr; the command exits non-zero on failure. - Resolve dirty state if needed. If migration fails partway through,
migrate upandmigrate downwill refuse to run withError: Database is in dirty state at version N. Inspect the schema, complete or revert the partial change manually, then runtalos migrate force <version>to mark the migration tracker. Never rerun on top of a dirty state. - Verify with
talos migrate status. Confirm the version matches the new binary's expected schema and thatSTATUSreportsOK, notDIRTY. - Roll the application. Start replicas of the new binary in a rolling deploy. Old replicas continue serving against the new schema until they are replaced.
Production safety
- Run
talos migrate upfrom a Job, init container, or operator — never from inside the application's startup path. Concurrent migration runners can deadlock or corrupt the migration tracker. - Pin the migration image to the same version as the application image. Do not use mutable tags (
latest,staging) for migration jobs. - Talos commercial migrations live under
commercial/persistence/migrations/{postgres,mysql,cockroach}/; the OSS image only ships SQLite migrations and cannot apply them. Use theoryd/talos-commercialimage for PostgreSQL, MySQL, and CockroachDB.
DSN examples
# SQLite (OSS)
talos migrate up --database "sqlite:///var/lib/talos/data.db"
# PostgreSQL (Commercial)
talos-commercial migrate up --database "postgres://talos:secret@db:5432/talos"
# MySQL (Commercial)
talos-commercial migrate up --database "mysql://talos:secret@tcp(db:3306)/talos?parseTime=true"
# CockroachDB (Commercial)
talos-commercial migrate up --database "cockroach://talos@crdb:26257/talos"
Kubernetes
Use a Job to apply migrations once, then start the application Deployment. The OSS image (oryd/talos:latest) only ships SQLite
migrations; for PostgreSQL, MySQL, or CockroachDB use oryd/talos-commercial:latest.
apiVersion: batch/v1
kind: Job
metadata:
name: talos-migrate
spec:
backoffLimit: 0 # Do not retry — a failed migration leaves the schema dirty.
template:
spec:
containers:
- name: migrate
image: oryd/talos-commercial:latest # Pin to the same tag as the application image.
command: ["talos", "migrate", "up"]
env:
- name: TALOS_DB_DSN
valueFrom:
secretKeyRef:
name: talos-secrets
key: dsn
restartPolicy: Never
