Ory Kratos uses automatic database migrations to keep your schema up to date. This guide explains how to run and manage migrations.
Migration overview
Kratos stores migration state in the database and automatically applies necessary schema changes. Migrations are idempotent and can be run multiple times safely.
Running migrations
Using the CLI
The primary way to run migrations is using the kratos migrate sql command:
kratos migrate sql -e --yes \
--config /path/to/kratos.yml
Read database DSN from environment variable DSN
Automatically confirm migration execution
Path to configuration file
Environment variable
Set the DSN via environment variable:
export DSN = "postgres://kratos:secret@postgres:5432/kratos?sslmode=require"
kratos migrate sql -e --yes
Migration commands
migrate sql up
migrate sql down
migrate sql status
Apply all pending migrations: kratos migrate sql -e --yes
This is the most common command and is used for both initial setup and upgrades. Rollback the last migration: kratos migrate sql down -e --yes
Downgrade migrations may result in data loss. Always backup your database first.
Check migration status: kratos migrate sql status -e
Shows applied and pending migrations.
Initial database setup
For a new deployment:
Create database
Create an empty database: CREATE DATABASE kratos ;
CREATE USER kratos WITH PASSWORD 'secure-password' ;
GRANT ALL PRIVILEGES ON DATABASE kratos TO kratos;
Set DSN
Configure the database connection: export DSN = "postgres://kratos:secure-password@localhost:5432/kratos?sslmode=require"
Run migrations
Apply the schema: kratos migrate sql -e --yes
Verify
Check that migrations succeeded: kratos migrate sql status -e
Upgrading Kratos
When upgrading to a new Kratos version:
Backup database
Always backup before upgrading: pg_dump -U kratos -h localhost kratos > backup- $( date +%Y%m%d ) .sql
Stop Kratos
Stop all running Kratos instances to prevent conflicts during migration.
Run migrations
Apply new migrations with the updated binary: kratos migrate sql -e --yes
Start Kratos
Start Kratos with the new version: kratos serve -c /path/to/kratos.yml
Docker deployments
Run migrations in Docker before starting the main service:
version : '3.7'
services :
kratos-migrate :
image : oryd/kratos:v25.4.0
environment :
- DSN=postgres://kratos:secret@postgres:5432/kratos?sslmode=require
volumes :
- ./config:/etc/config/kratos
command : -c /etc/config/kratos/kratos.yml migrate sql -e --yes
restart : on-failure
networks :
- intranet
kratos :
depends_on :
- kratos-migrate
image : oryd/kratos:v25.4.0
# ... rest of configuration
Kubernetes deployments
Use a Kubernetes Job to run migrations:
apiVersion : batch/v1
kind : Job
metadata :
name : kratos-migrate-{{ .Release.Revision }}
namespace : kratos
annotations :
"helm.sh/hook" : pre-install,pre-upgrade
"helm.sh/hook-weight" : "1"
"helm.sh/hook-delete-policy" : before-hook-creation
spec :
backoffLimit : 10
template :
spec :
restartPolicy : Never
containers :
- name : migrate
image : oryd/kratos:v25.4.0
command :
- kratos
args :
- migrate
- sql
- -e
- --yes
- --config
- /etc/config/kratos.yml
env :
- name : DSN
valueFrom :
secretKeyRef :
name : kratos-secrets
key : dsn
volumeMounts :
- name : config
mountPath : /etc/config
volumes :
- name : config
configMap :
name : kratos-config
CI/CD integration
GitHub Actions
name : Deploy Kratos
on :
push :
branches : [ main ]
jobs :
deploy :
runs-on : ubuntu-latest
steps :
- name : Checkout
uses : actions/checkout@v3
- name : Run migrations
env :
DSN : ${{ secrets.KRATOS_DSN }}
run : |
docker run --rm \
-e DSN="$DSN" \
-v $(pwd)/config:/etc/config \
oryd/kratos:v25.4.0 \
migrate sql -e --yes
- name : Deploy Kratos
run : |
# Your deployment script
GitLab CI
migrate :
stage : deploy
image : oryd/kratos:v25.4.0
script :
- kratos migrate sql -e --yes
only :
- main
environment :
name : production
variables :
DSN : $KRATOS_DSN
Migration safety
Always follow these safety practices when running migrations:
Backup first
Always create a database backup before running migrations.
Test in staging
Run migrations in a staging environment first to identify issues.
Stop writes
Stop all Kratos instances before running migrations to prevent conflicts.
Monitor
Watch migration output for errors or warnings.
Verify
Check migration status after completion: kratos migrate sql status -e
Troubleshooting
If migrations hang or timeout:
Check for other running Kratos instances
Look for stale migration locks in the database
Increase timeout (if needed)
Clear stale locks (use with caution): -- PostgreSQL
DELETE FROM schema_migration WHERE dirty = true;
If a migration fails:
Review error messages in output
Check database logs
Restore from backup if needed
Contact Ory support with error details
Ensure the database user has proper permissions: -- PostgreSQL
GRANT ALL PRIVILEGES ON DATABASE kratos TO kratos;
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO kratos;
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO kratos;
Verify DSN format and network connectivity: # Test connection
psql " $DSN "
# Verify DSN is correct
echo $DSN
Migration versioning
Kratos migrations are tied to release versions. When upgrading:
Patch versions (e.g., v25.4.0 → v25.4.1): Usually no new migrations
Minor versions (e.g., v25.4.0 → v25.5.0): May include new migrations
Major versions (e.g., v25.0.0 → v26.0.0): Often include breaking migrations
Next steps
Configuration Configure Kratos for production
Database setup Learn about database options