The migration was supposed to be simple. One table. One new column. Yet this is where systems break, data warps, and deadlines slip.
Adding a new column in a production database is never just adding a new column. It changes the schema, affects queries, and touches code paths you forgot existed. Every ORM mapping, every API response, every consumer that reads that table could be impacted. If you ignore those edges, you trade minutes now for hours of debug later.
In SQL, ALTER TABLE feels harmless:
ALTER TABLE users ADD COLUMN last_login_at TIMESTAMP;
On an idle development database, it is instant. On tables with millions of rows, it can lock writes, block reads, or force a table copy. Postgres, MySQL, and SQLite handle schema changes differently, and with large datasets, the wrong approach can cause downtime. Many teams schedule it for off-peak hours. Others use online schema change tools like pt-online-schema-change or gh-ost to keep the application live.
Application code must adapt before and after the migration. Adding a nullable column is safest, but constraints enforce integrity. If you set NOT NULL with a default, the database may write or rewrite every row. Consider creating the column as nullable, updating rows in batches, then altering to add the constraint. This reduces lock times and spreads the load.