Separate code rollback from data recovery
Before deploying, identify every stateful change: schema updates, background jobs, object formats, and external API effects. Prefer reversible or backward-compatible changes, and record which release can safely read each data version.
If a migration is destructive, take and verify a recovery point before it runs. Restoring a full database snapshot can erase legitimate writes made after that snapshot, so compare the impact of restore with a forward fix or a targeted repair.
Use a controlled rollback procedure
Choose the previous known-good release, route traffic back, and confirm health checks and core user journeys. Pause incompatible workers or scheduled jobs so old code does not process data written in a new format.
After service stabilizes, reconcile records and background work created during the incident, then document the cause and safeguards. Test the rollback procedure periodically; a release artifact alone does not prove that the service can be restored safely.