Changing a database column is easy to describe when one application process owns the database and can stop for the change. A deployed service often has a messier interval: old and new application instances may run at the same time.

That interval is where a simple column rename can break otherwise correct code. The new version asks for the new name while the old version still asks for the old one.

Add before removing

Suppose customers.name needs to become customers.display_name. An illustrative transition is:

  1. Add the new nullable column while keeping the old column usable.
  2. Deploy code that writes both values in the same transaction and can read through the transition.
  3. Backfill existing rows in bounded batches, with a retry-safe condition.
  4. Check that all writers have migrated and the backfill is complete.
  5. Switch reads to the new field; remove the old field in a later change.

The details depend on the database and workload. A batch backfill can race with live updates, and a forgotten background job may still write only the old column. The compatibility plan needs to include those writers, not just the web application.

Separate reversible steps

Before removing a column, rolling the application back may still be straightforward. After deletion, the previous code can no longer rely on the data it expects. Treat that deletion as a separate decision with its own verification and recovery plan.

The SQL statement’s apparent simplicity also says little about its operational cost. Check the database version’s behaviour for locks, table scans and constraint validation. Rehearse on a representative dataset when those costs could interrupt traffic.

A useful migration note explains what can run during each stage, how completion is checked, and what rollback means at that point. That note is often more valuable than a clever one-line migration.

Reference: PostgreSQL documentation on modifying tables.