Adding a new column should be simple, but in production systems, simplicity doesn’t mean easy. Every column carries schema changes, data transformations, index updates, and the risk of downtime. The challenge compounds when databases grow large, query performance is tight, and zero-downtime deployment is non-negotiable.
A new column can introduce subtle failure modes. Default values might trigger full-table rewrites. Queries that expect NULL can break under NOT NULL constraints. Adding the column without an index can turn hot paths cold in milliseconds. Adding it with the wrong index can inflate storage and slow writes for years.
Best practice is to treat schema evolution as code. Start with a migration that introduces the column in a non-blocking way—NULLable, no default value applied to existing rows. Monitor query plans before and after. Update your application to write to the new column while still reading from the old source of truth. Backfill data in controlled batches, measuring I/O and replication lag. Only after full population and validation should you apply constraints or indexes.