chkit migrate
Applies pending migration SQL files to your ClickHouse instance. Supports plan-only mode, interactive confirmation, destructive operation safety, and checksum verification.
Synopsis
Section titled “Synopsis”chkit migrate [flags]| Flag | Type | Default | Description |
|---|---|---|---|
--apply | boolean | false | Apply pending migrations without prompting |
--execute | boolean | false | Alias for --apply |
--allow-destructive | boolean | false | Allow destructive operations (required in non-interactive mode) |
--table <selector> | string | — | Scope migrations to those affecting matching tables |
Global flags documented on CLI Overview.
Behavior
Section titled “Behavior”Plan vs execute
Section titled “Plan vs execute”By default, chkit migrate shows the list of pending migrations without applying them. Pass --apply (or --execute) to apply.
In interactive mode (TTY), the CLI prompts for confirmation before applying. In non-interactive mode (CI, piped input), --apply is required — otherwise the command only reports the plan.
CI / non-interactive detection
Section titled “CI / non-interactive detection”The CLI detects non-interactive contexts when any of these conditions are true:
CI=1orCI=trueenvironment variable is set- stdin is not a TTY
- stdout is not a TTY
Destructive operation safety
Section titled “Destructive operation safety”Migration files containing risk=danger operations (such as DROP TABLE or DROP COLUMN) require explicit approval:
- Interactive mode: the CLI prompts for confirmation
- Non-interactive / CI mode:
--allow-destructivemust be passed, orsafety.allowDestructivemust betruein config. Otherwise the command exits with code 3. - JSON mode: exits with code 3 and includes details about blocked operations
Each destructive operation includes a warning code, reason, impact description, and recommendation:
| Warning code | Operation |
|---|---|
drop_table_data_loss | DROP TABLE |
drop_column_irreversible | DROP COLUMN |
drop_view_dependency_break | DROP VIEW / DROP MATERIALIZED VIEW |
destructive_operation_review_required | Other destructive operations |
Checksum verification
Section titled “Checksum verification”Before applying, the CLI verifies SHA-256 checksums of all previously-applied migrations against the files on disk. If any file has been modified since it was applied, the command aborts with exit code 1.
Journal
Section titled “Journal”Each applied migration is recorded in the _chkit_migrations journal table in ClickHouse with:
name— the migration filenameappliedAt— ISO 8601 timestampchecksum— SHA-256 hash of the file content
The journal is written after each migration, not batched. The table is created in the database configured in clickhouse.database (it is not qualified with a database name, so on a shared/default-database setup it lives in default._chkit_migrations). The table name can be overridden with the CHKIT_JOURNAL_TABLE environment variable.
Table scoping
Section titled “Table scoping”The --table flag filters pending migrations to those containing operations targeting the matched tables. Migration SQL files are parsed for -- operation: comment markers to determine which tables they affect.
Plugin hooks
Section titled “Plugin hooks”The onBeforeApply plugin hook runs before each migration is executed and can transform the SQL statements. The onAfterApply hook runs after successful execution.
Examples
Section titled “Examples”Preview pending migrations:
chkit migrateApply in CI:
chkit migrate --apply --jsonApply with destructive operations allowed:
chkit migrate --apply --allow-destructiveScope to a specific table:
chkit migrate --apply --table analytics.eventsExit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
| 0 | Success (or no pending migrations) |
| 1 | Checksum mismatch on applied migrations |
| 3 | Destructive operations blocked |
JSON output
Section titled “JSON output”Plan mode
Section titled “Plan mode”{ "command": "migrate", "schemaVersion": 1, "mode": "plan", "scope": { "enabled": false }, "pending": ["20260604104251_add_column.sql", "20260604105133_create_index.sql"]}Successful execution
Section titled “Successful execution”{ "command": "migrate", "schemaVersion": 1, "mode": "execute", "scope": { "enabled": false }, "applied": [ { "name": "20260604104251_add_column.sql", "appliedAt": "2025-06-15T10:30:00.000Z", "checksum": "a1b2c3..." } ]}Checksum mismatch error
Section titled “Checksum mismatch error”{ "command": "migrate", "schemaVersion": 1, "mode": "execute", "scope": { "enabled": false }, "error": "Checksum mismatch detected on applied migrations", "checksumMismatches": [ { "name": "20260604090000_init.sql", "expected": "abc123...", "actual": "def456..." } ]}Destructive operations blocked
Section titled “Destructive operations blocked”{ "command": "migrate", "schemaVersion": 1, "mode": "execute", "scope": { "enabled": false }, "error": "Blocked destructive migration execution. Re-run with --allow-destructive or set safety.allowDestructive=true after review.", "destructiveMigrations": ["20260605112000_drop_old_table.sql"], "destructiveOperations": [ { "migration": "20260605112000_drop_old_table.sql", "type": "drop_table", "key": "default.old_table", "risk": "danger", "warningCode": "drop_table_data_loss", "reason": "...", "impact": "...", "recommendation": "...", "summary": "..." } ]}Per-migration metadata
Section titled “Per-migration metadata”Migration files can declare optional metadata in the leading comment header. chkit migrate reads these keys and uses them to inform the user before the migration runs.
| Key | Effect |
|---|---|
log | Printed to stdout immediately before the migration is applied. Use it to flag long-running or risky operations. |
Example header:
-- chkit-migration-format: v1-- log: Loading the full ClickBench dataset (~100M rows). Expected duration: 3-5 minutes.-- generated-at: ...-- ...
INSERT INTO default.hits SELECT * FROM s3(...);When the migration is listed (plan mode and as part of --apply):
Pending migrations: 1- 20260525133130_load_clickbench_data.sql Loading the full ClickBench dataset (~100M rows). Expected duration: 3-5 minutes.In --apply mode the log line is also re-printed immediately before each migration is executed, so the message stays close to the related work in CI logs:
Loading the full ClickBench dataset (~100M rows). Expected duration: 3-5 minutes.Applied: 20260525133130_load_clickbench_data.sqlMetadata keys are parsed from contiguous -- key: value comments at the top of the file (blank lines are tolerated) and stop at the first non-comment line. Unknown keys are ignored, so adding new keys in future releases is backwards-compatible.
Related commands
Section titled “Related commands”chkit generate— produce migration files from schema changeschkit status— check migration state without applyingchkit check— CI gate that evaluates pending migrations and checksums