There are two separate failure modes, and each needs its own defense.
Locks. Most schema changes need an exclusive lock on the table. The safe-pg-migrations project from Doctolib explains that most DDL operations, such as adding a column, removing a column or adding a default value, take an ACCESS EXCLUSIVE lock on the table they are altering, and other statements are blocked while they wait. RunxBuild's guide adds that this is the strongest lock PostgreSQL has, blocking reads and writes alike. A change that takes this lock for milliseconds is harmless. One that holds it while it scans or rewrites a large table is an outage.
Mixed versions. During a deploy, old and new application code run at the same time. Harness puts the principle plainly: a migration should never assume that the new application version is the only code touching the database, because during a rolling deployment, blue-green cutover or staged rollout, both versions may run side by side. If you rename a column in the same release that starts using the new name, the old instances still query the old name and fail until they are replaced. A rollback to the previous version fails the same way.
The rest of this article deals with both: keep locks short, and keep every schema state compatible with the code on either side of it.



