Adding a new column sounds trivial. It rarely is. Schema changes touch code, data, and live traffic all at once. A single misstep can lock a table, stall writes, or break critical queries. The goal is zero downtime, exact precision, and a repeatable process.
First, define the new column in a migration file. Use explicit data types, defaults, and constraints. Avoid null when possible; it hides problems until they explode. For large tables, adding a column with a default value can cause a full table rewrite. On PostgreSQL, use ALTER TABLE … ADD COLUMN without a default, then backfill in small batches. On MySQL, check for online DDL support and avoid locking on production traffic.
Second, deploy migrations in phases. Add the new column. Deploy code that writes to it. Backfill historical data with a controlled script. Then switch reads to the new column once it’s fully populated. Phase rollouts reduce risk and allow quick rollback if something goes wrong.