Adding a new column sounds simple. In production, it is often where downtime, errors, and failed deploys begin. Schema changes touch live data. They block writes if locked. They break code if deployed in the wrong order. Done wrong, a new column can corrupt tables or stall queries under load.
To add a new column safely, treat the database like a moving target. Step one: add the column with a non-blocking migration. In PostgreSQL, ALTER TABLE ... ADD COLUMN without a default can be instant. If you need a default, set it in application logic first, backfill in small batches, then apply the default constraint after data exists.
Step two: deploy code that can handle nulls. Until the column is fully populated, every query must tolerate missing values. Step three: backfill without locking rows for long periods. Use UPDATE ... WHERE with limits and pauses between batches to avoid saturating I/O. Monitor indexes. Adding an index on the new column should also be non-blocking, using CREATE INDEX CONCURRENTLY in PostgreSQL or equivalent options in other systems.