Use AI to Write Database Migrations Safely
AI can write database migrations fast, but a bad migration loses data you cannot get back. Here is how to use AI on schema changes without a disaster.
AI can write a database migration in seconds, and that speed is exactly why it is dangerous. Most AI coding mistakes are recoverable: you revert the commit, you fix the bug, you move on. A bad migration is different. It can drop a column, rewrite data in place, or lock a table for hours, and some of that you cannot undo. The code you can roll back. The data you deleted is gone. So database migrations are the one area where you slow down, review every line yourself, and never let the model run the change unsupervised.
Why migrations are the high-stakes exception
A migration is code that touches state you cannot regenerate. A feature bug annoys users until you fix it. A migration that runs UPDATE with a wrong WHERE clause corrupts production data permanently. The blast radius is not the code, it is the business's records.
The model does not feel this weight. It will produce a syntactically perfect migration that happens to be catastrophic, with the same cheerful confidence it uses for a CSS tweak. That is why this is the place to break the usual "let it run" habit. It is the same care you would demand from any migration, enforced harder because the author has no fear.
Let AI draft, never let it decide
Use the model for what it is good at: drafting the mechanical migration, generating the up and down scripts, writing the boilerplate for adding a column or an index. Then treat that draft as a proposal from a junior who has never seen production, because that is what it is.
Review every migration for the specific ways they go wrong:
- Destructive operations. Any
DROP, anyUPDATEwithout a tightWHERE, any type change that can lose precision. The model will write these without flagging the danger. - Missing down migration. If it cannot be rolled back, that is a design decision you make consciously, not one the model makes by omitting it.
- Locking behavior. A migration that rewrites a large table can lock it for the duration. On a live database that is downtime. The model rarely accounts for table size.
- Data assumptions. A migration that assumes every row has a value in a column that is sometimes null will fail halfway, leaving a half-migrated table. That is worse than not running.
Expand and contract, never rewrite in place
The safe pattern for schema changes under load is expand and contract, and it is worth telling the model to use it. Add the new column, backfill it, switch the app to read it, then drop the old one in a later migration. Each step is reversible. Compare that to renaming a column in one shot, which breaks every running instance of the app that still expects the old name.
This is the same small-steps principle behind refactoring with AI in small, safe steps: break the scary change into reversible pieces so no single step can take you down. The model will happily write the one-shot version because it is shorter. Do not accept it.
Test the migration against real-shaped data
A migration that works on an empty dev database can fail on production data with its nulls, its duplicates, its edge cases. Run it against a copy of real data, or realistic-shaped data, before it goes near production. And have point-in-time recovery actually working before you run anything destructive, because "we can restore" is only true if you have tested the restore. Then review the generated migration as a unit, because this is the diff where reading every line yourself is non-negotiable.
This is exactly how migrations flow through Bootspring: the model drafts, the change is gated, destructive operations are flagged, and nothing touches production data without a human reading every line first.
The takeaway
Database migrations are the one place to break the "let AI run" habit. Let the model draft the migration, then review every line yourself for destructive operations, missing rollbacks, locking, and bad data assumptions. Use expand-and-contract so every step is reversible, test against real-shaped data, and confirm your restore works before anything destructive runs. Code you can roll back. Deleted data you cannot.