The migration script had stalled on a single command: add a new column.
A new column sounds simple. In production, it can break everything. Schema changes lock tables. Queries queue up and pile pressure on your database. Downtime is expensive. Integrity errors are worse.
Adding a new column safely means understanding how your database engine handles DDL changes. PostgreSQL can add a new column with a default value instantly if it’s nullable or has a constant. MySQL might rewrite the entire table depending on engine settings. Large datasets turn milliseconds into minutes.
For high-traffic systems, you plan schema changes like code deploys. You test on staging with production-like data. You measure lock times. You break down operations into small, atomic steps. Sometimes you create the new column without defaults, backfill data in batches, and only then enforce constraints or indexes.