Database migration safety

Check the SQL the migration tool will actually execute

A short ORM change can generate a costly or incompatible database operation. Review the emitted SQL and its production consequences before approval.

In this article

Compare intent with execution

A developer may intend to make a field easier to query, while the generated migration changes its type, rebuilds an index or replaces a column. Review the SQL rather than relying only on the application model diff.

Confirm table and column names, defaults, constraints and dependency changes. Look for accidental drops caused by renaming a model property without an explicit database rename or transition.

Check the migration against the exact database version. Behaviour remembered from another engine or release is not sufficient evidence for a production change.

Examine waiting and work

Determine the lock requirements and whether the command scans or rewrites data. Consider long-running transactions and concurrent application writes.

For PostgreSQL, concurrent index creation has different execution restrictions from a regular index build, including that it cannot run inside a transaction block. A migration tool that wraps every step in a transaction needs an appropriate mechanism for such a command.

Review waiting limits, progress visibility and cleanup after failure. A safe command without a safe execution wrapper can still produce a difficult incident.

Inspect the data assumptions

Before adding a constraint, establish whether existing rows satisfy it. Define how exceptions are resolved and who approves any business-data correction.

Check conversion boundaries such as precision, length, nullability and timezone interpretation. A syntactically valid cast may lose information or assign a meaning the old data never had.

Review live writers during the backfill. They must not create new violations faster than the migration repairs old ones. Validation of a static snapshot alone cannot establish the final invariant.

Require a recovery demonstration

Run the migration, interrupt it at a meaningful point and resume from the observed state. Exercise the supported old and new application versions against the result.

For destructive changes, state what recovery preserves and what it cannot. A reverse migration that recreates an empty column does not restore the values that were dropped.

Attach concise evidence to the review: the executed SQL, representative rehearsal results, unresolved data exceptions and the rollback boundary. These details let a reviewer assess the real operation instead of approving a reassuring migration filename.

Primary sources

PostgreSQL: CREATE INDEXPostgreSQL: ALTER TABLE

References checked 11 September 2026.