Loading...
Loading...
Use when planning or reviewing production database migrations, adding columns, indexes, constraints, backfills, renames, table rewrites, or concurrent operations. Covers phased rollouts, lock behavior, rollback strategy, strong_migrations compliance, and deployment ordering for schema changes.
npx skill4agent add igmarin/rails-agent-skills rails-migration-safety| Operation | Safe Pattern |
|---|---|
| Add column | Nullable first, backfill later, enforce NOT NULL last |
| Add index (large table) | |
| Backfill data | Batch job, not inside migration transaction |
| Rename column | Add new, copy data, migrate callers, drop old |
| Add NOT NULL | After backfill confirms all rows have values |
| Add foreign key | After cleaning orphaned records |
| Remove column | Remove code references first, then drop column |
DO NOT combine schema change and data backfill in one migration.
DO NOT add NOT NULL on a column that hasn't been fully backfilled.
DO NOT drop columns before all code references are removed.NOT NULLstrong_migrationsadd_column :orders, :status, :string, default: 'pending', null: false
Order.update_all("status = 'pending'")# Step 1: add nullable column
add_column :orders, :status, :string
# Step 2 (separate deploy): backfill in batches outside migration
# Step 3 (after backfill): add constraint
change_column_null :orders, :status, false
change_column_default :orders, :status, from: nil, to: 'pending'# PostgreSQL: concurrent index (no write lock)
disable_ddl_transaction!
add_index :orders, :processed_at, algorithm: :concurrent
# MySQL: online DDL
add_index :orders, :processed_at, algorithm: :inplace| Mistake | Reality |
|---|---|
| "Table is small, no need for phased migration" | Tables grow. Build the habit for all migrations. |
| Schema change + backfill in one migration | Long transaction, long lock. Always separate them. |
| Column rename with immediate app cutover | App will crash during deploy. Use add-copy-migrate-drop. |
| Exclusive lock on large PostgreSQL tables blocks writes. |
| Adding NOT NULL before backfill completes | Migration fails or locks table waiting for backfill. |
| Removing column before removing code references | App crashes when accessing the missing column. |
| Skill | When to chain |
|---|---|
| rails-code-review | When reviewing PRs that include migrations |
| rails-background-jobs | For backfill jobs that run after schema change |
| rails-security-review | When migrations expose or move sensitive data |