Docs/Commands/migrate
OSSgenerated from cli/_parser_setup.py

dblift migrate

Apply migrations. Runs every pending migration in version order and records each one in the schema history table.

Synopsis

$ dblift migrate [--target-version VERSION] [--validate-only]
                [--tags TAGS] [--exclude-tags TAGS]
                [--versions LIST] [--exclude-versions LIST]
                [--placeholders K=V [K=V ...]]
                [--strict] [--table TABLE]

Options

FlagDescription
--tableCustom schema history table name (default: dblift_schema_history)
--strictEnable strict mode - fail if any previously applied migration is missing and require migrations to be applied in strict version order
--tagsExecute migrations with specified tags (comma-separated list)
--exclude-tagsSkip migrations with specified tags (comma-separated list)
--versionsExecute only specific versions (comma-separated list)
--exclude-versionsSkip specific versions (comma-separated list)
--placeholdersSQL placeholders for variable substitution in migration scripts. Format: key1=value1,key2=value2 or key1=value1 key2=value2. Can be repeated: --placeholders k1=v1 --placeholders k2=v2
--db-urlDatabase URL
--db-usernameDatabase username
--db-passwordDatabase password
--db-schemaDatabase schema
--target-versionTarget version to migrate to
--validate-onlyOnly validate migrations without applying them
--mark-as-executedMark migrations as executed without running them (for migration applied outside dblift)
--show-sqlShow SQL statements in command output and reports
--show-query-resultsShow rows returned by SELECT statements in command output and reports
--formatOutput format (default: console)

Filters

By default migrate applies every pending versioned file, then any repeatable whose checksum changed. Narrow that set with tags (from the filename), an explicit version list, or a ceiling version. Matching is case-sensitive. Callbacks (`beforeMigrate__*.sql` and the rest) still run around the selected scripts.

Preview only files tagged auth — V1_2_0__add_note[auth].sql in this tree. core files stay pending.

$ dblift migrate --tags=auth --dry-run --show-sql
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00                                                                                       ┃
┃ Dblift version: 3.9.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database ./app.db (SQLite)                                                                              ┃
┃ Database: ./app.db                                                                                                   ┃
┃ Schema: main                                                                                                         ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┃ Database URL: sqlite:///./app.db                                                                                     ┃
┃ Filtering Options: --dry-run --tags=auth --show-sql                                                                  ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 pending migration(s)
WARNING: Placeholder '${TABLE_NAME}' not found, leaving as is
WARNING: Placeholder '${LABEL_VALUE}' not found, leaving as is
DRY RUN: Would execute the following migrations:
  - V1_2_0__add_note[auth].sql
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   - Dry run — 1 migration(s) would be applied                                                                        ┃
┃ Command MIGRATE completed successfully (Execution time: 12 ms)                                                       ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
SQL Statements:
--------------------------------------------------------------------------------
-- V1_2_0__add_note[auth].sql
ALTER TABLE ${TABLE_NAME} ADD COLUMN note TEXT DEFAULT '${LABEL_VALUE}';
--------------------------------------------------------------------------------

Preview a single version. Combine with --exclude-versions or --exclude-tags to skip others.

$ dblift migrate --versions 1.1.0 --dry-run --show-sql
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00                                                                                       ┃
┃ Dblift version: 3.9.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database ./app.db (SQLite)                                                                              ┃
┃ Database: ./app.db                                                                                                   ┃
┃ Schema: main                                                                                                         ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┃ Database URL: sqlite:///./app.db                                                                                     ┃
┃ Filtering Options: --dry-run --versions=1.1.0 --show-sql                                                             ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 callback migrations.
Found 1 pending migration(s)
DRY RUN: Would execute the following migrations:
  - V1_1_0__users_created_at[core].sql
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   - Dry run — 1 migration(s) would be applied                                                                        ┃
┃ Command MIGRATE completed successfully (Execution time: 12 ms)                                                       ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
SQL Statements:
--------------------------------------------------------------------------------
-- V1_1_0__users_created_at[core].sql
ALTER TABLE users ADD COLUMN created_at TEXT;
--------------------------------------------------------------------------------

Placeholders

SQL files may contain `${NAME}` or `${NAME:default}`. Values come from config `placeholders:`, then `--placeholders`. Two spellings are accepted: a comma-separated string, or repeated `KEY=value` tokens. Unresolved tokens are left as-is and a warning is logged. Python migrations read `context.placeholders` — they are not substituted automatically.

Substitute TABLE_NAME and LABEL_VALUE before the statements run.

$ dblift migrate --placeholders TABLE_NAME=users LABEL_VALUE=hello --dry-run --show-sql
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00                                                                                       ┃
┃ Dblift version: 3.9.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database ./app.db (SQLite)                                                                              ┃
┃ Database: ./app.db                                                                                                   ┃
┃ Schema: main                                                                                                         ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┃ Database URL: sqlite:///./app.db                                                                                     ┃
┃ Filtering Options: --dry-run --show-sql                                                                              ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 callback migrations.
Found 2 pending migration(s)
DRY RUN: Would execute the following migrations:
  - V1_1_0__users_created_at[core].sql
  - V1_2_0__add_note[auth].sql
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   - Dry run — 2 migration(s) would be applied                                                                        ┃
┃ Command MIGRATE completed successfully (Execution time: 12 ms)                                                       ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
SQL Statements:
--------------------------------------------------------------------------------
-- V1_1_0__users_created_at[core].sql
ALTER TABLE users ADD COLUMN created_at TEXT;
-- V1_2_0__add_note[auth].sql
ALTER TABLE users ADD COLUMN note TEXT DEFAULT 'hello';
--------------------------------------------------------------------------------

Callbacks

A file named `{event}__{description}.sql` is not a migration. It runs at that point in the lifecycle — `beforeMigrate`, `afterEachMigrate`, `afterMigrateError`, and the others listed under Naming conventions. Put session setup there (lock timeouts, `PRAGMA`, `SET search_path`). Tags on a callback filename work the same way as on a versioned file.

Dry run and --show-sql

`--dry-run` applies nothing and does not create the schema-history table. `--show-sql` prints the statements that would run. With `--format json`, and only when `--show-sql` is set, the payload adds `show_sql: true` and a `sql` array of pending scripts, each with `script`, `version`, `description`, and `statements`. Placeholders that resolve are substituted, so a secret used as a placeholder value appears in that SQL. A placeholder with no value stays visible as `${VAR}`. The MCP `migrate_dry_run` tool takes `show_sql` (default false) and returns the same shape. It needs a live connection; `dblift mcp --offline` refuses the call. The tool never applies.

Global flags apply to every command: --config, --env, --scripts, --dry-run, --quiet, --log-level. See global flags.

Examples

Preview the exact SQL before it runs

$ dblift migrate --dry-run --show-sql
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00                                                                                        ┃
┃ Dblift version: 3.9.0                                                                                                 ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database ./app.db (SQLite)                                                                               ┃
┃ Database: ./app.db                                                                                                    ┃
┃ Schema: main                                                                                                          ┃
┃ Schema Version: <none>                                                                                                ┃
┃ Database URL: sqlite:///./app.db                                                                                      ┃
┃ Filtering Options: --dry-run --show-sql                                                                               ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 callback migrations.
Found 1 pending migration(s)
DRY RUN: Would execute the following migrations:
  - V1_0_0__create_users[core].sql
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃   - Dry run — 1 migration(s) would be applied                                                                         ┃
┃ Command MIGRATE completed successfully (Execution time: 12 ms)                                                        ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
SQL Statements:
--------------------------------------------------------------------------------
-- V1_0_0__create_users[core].sql
CREATE TABLE users (
    id    INTEGER PRIMARY KEY AUTOINCREMENT,
    name  TEXT NOT NULL,
    email TEXT NOT NULL UNIQUE
);
--------------------------------------------------------------------------------

Apply every pending file

$ dblift migrate
┏━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT DATABASE MIGRATION LOG ━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Timestamp: 2026-01-15 12:00:00                                                                                       ┃
┃ Dblift version: 3.9.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ DBLIFT COMMAND: MIGRATE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Connected to database ./app.db (SQLite)                                                                              ┃
┃ Database: ./app.db                                                                                                   ┃
┃ Schema: main                                                                                                         ┃
┃ Schema Version: <none>                                                                                               ┃
┃ Database URL: sqlite:///./app.db                                                                                     ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
Found 1 callback migrations.
Found 1 pending migration(s)
Migration lock acquired successfully
Executing 1 beforeMigrate callback(s)
Executing callback: beforeMigrate__set_pragma.sql
Statement executed successfully, 0 rows affected
Callback beforeMigrate__set_pragma.sql executed successfully

⠋ Migrating                                          0/1 0:00:00
Statement executed successfully
⠋ Migrating                                          0/1 0:00:00
Migration V1_0_0__create_users[core].sql executed successfully in 0ms
⠋ Migrating                                          0/1 0:00:00
Successfully applied migration V1_0_0__create_users[core].sql
⠋ Migrating                                          0/1 0:00:00
  V1_0_0__create_users.sql ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 1/1 0:00:00

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ SUCCESS ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Command MIGRATE completed successfully (Execution time: 12 ms)                                                       ┃
┃ Schema Version: 1.0.0                                                                                                ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛

Exit codes

CodeMeaning
0Command completed successfully
4A paid-edition feature was invoked without a valid licence (EXIT_LICENSE_REQUIRED)
On this page