← All resources
Blog

Rollback Is a Story Until You Test It

Every team says they can reverse a database change. Very few have ever tried.

Simcha Solutions · 2026-08-02

Ask a team whether they can roll back a database change and the answer is almost always yes. Ask when they last actually did it, on purpose, against a realistic copy of production, and the room goes quiet. That silence is the honest answer. For most teams, rollback is not a capability. It is a story they tell themselves during change review, and the first real test of the story is the worst possible moment: mid-incident, with the application down and everyone watching.

Why the story rots

The rollback story fails for boring, structural reasons, not because anyone is careless.

Down-scripts age faster than up-scripts. The forward migration gets exercised constantly: in development, in CI, in staging, in production. The reverse script gets written once, at the same time as the forward one, and then never runs again. Every subsequent change to the forward path quietly invalidates assumptions in the reverse path, and nothing fails until the day you need it.

Some changes have no true inverse. Dropping a column discards data that a reverse migration cannot summon back. Tightening a constraint after bad rows were cleaned means the "reverse" recreates a schema, not a state. Type narrowing, precision changes, and destructive backfills all share the property that the schema can be reversed while the data cannot. A rollback plan that does not distinguish these two cases is not a plan.

The reverse path is rarely reviewed. Change review scrutinizes what a migration will do. The question "and how exactly do we undo this, and what is lost if we do" is asked far less often, and almost never answered with something executable.

What a real reverse path looks like

The teams that can genuinely roll back treat the reverse path as part of the change itself, with the same standards as the forward path.

  • Written at change time, from live state. The reliable reverse script is generated against the actual pre-change state of the target, not reconstructed later from memory or from the migration history.
  • Explicit about irreversibility. Where a step cannot be undone, the plan says so before execution, so the approval is made knowing what is at stake. "This drops data; the rollback restores schema only" is a sentence that belongs in the review, not the postmortem.
  • Tested the way forward migrations are tested. Run the reverse against a restored copy on a schedule. A reverse script that has executed successfully against yesterday's production snapshot is evidence. Anything else is optimism.
  • Stored with the change, not beside it. The rollback belongs to the same record as the migration it reverses: same review, same audit trail, same place you look at two in the morning.

The uncomfortable test

Here is a one-question audit of your database change process: pick the last schema change that shipped, and ask what single command reverses it right now. If the answer involves someone writing SQL from scratch under pressure, your rollback is a story. If the answer is a reviewed, tested artifact sitting next to the change that created the need for it, you have a capability.

The difference between the two is invisible on every deploy that goes well, which is why the story survives so long. It only becomes visible on the deploy that goes wrong, and by then it is the difference between a decision and an improvisation.