A database migration can work perfectly on your development machine and still make a production deployment awkward. During a rolling release, some application instances may be running the old code while others use the new code. If the schema change immediately removes something the old version expects, the deployment order becomes a trap.
The expand-and-contract approach separates adding the new structure from removing the old one. Introduce a compatible shape, move the application and data across, then remove the obsolete structure when it is genuinely unused. It creates more than one step, but each step has a clearer relationship with the code currently running.
I would pay particular attention to data written during the transition. A backfill of yesterday’s rows does not automatically handle today’s new writes, and a rollback may be useless if the older application cannot understand the updated records. Decide how those cases work before treating a successful migration command as proof that the release is safe.
Small deployments are easier to manage when the database lets the application move gradually. The aim is a change you can explain and recover from, with checks at each boundary. Saving one migration file is not worth making every instance switch versions at exactly the same moment.