Back to articles
Production-level
12 min read

Why Rollbacks Fail in Production

A production-focused analysis of why rollbacks fail when code, data, configuration, side effects, and ownership are not designed for recovery.

release-engineeringrollbackincident-responsedeployment-automationdevopsproductionarchitecture
João Gustavo Camilo JúniorEngineering Lead
Engineering

Why Rollbacks Fail in Production

Rollback is not a plan.

Rollback is a claim about reversibility.

That claim is often false.

Teams say "we can roll back" because the deployment tool has a button, Kubernetes can undo a rollout, the previous container image still exists, or the last artifact can be redeployed. Those mechanisms matter. They are not enough.

Production state moves.

Data changes. Messages are published. Emails are sent. Caches are warmed with new shapes. Feature flags are flipped. Customers see behavior. Jobs process work. External systems accept requests. Other services adapt to the new version.

Reinstalling the previous artifact does not reverse all of that.

The hard part of rollback is not moving code backward.

The hard part is knowing whether the system can safely move backward after production has already moved forward.

The Context Behind Failed Rollbacks

Most rollback procedures are written for the simple case.

A service deploys a bad build. The team returns to the previous image. Traffic stabilizes. Incident closed.

That case exists.

It is also the least interesting one.

Real production failures usually involve state. A deployment changes a database schema, a queue payload, a cache key, a provider integration, a background worker, a permission decision, or a workflow boundary. The deployment may only take five minutes, but the system begins creating new facts immediately.

Rollback then becomes a distributed systems problem.

DORA's continuous delivery guidance frames low-risk release as the ability to make production changes quickly, safely, and sustainably. It also measures time to restore service after failure. That metric matters because rollback is only one restoration strategy. Sometimes the fastest restoration is rollback. Sometimes it is disabling a feature flag. Sometimes it is stopping a worker. Sometimes it is rolling forward with a compensating fix.

Google SRE's release engineering material makes a similar point from the release discipline side: repeatability, automation, consistency, and auditability are release properties. They are also rollback properties.

If the release cannot be identified, reproduced, observed, and reversed in a controlled way, the rollback path is mostly hope.

The Problem Is Reversibility

Production rollback fails when the system confuses artifact rollback with state rollback.

Those are different operations.

Artifact rollback returns code or configuration to a previous version.

State rollback returns the world to a previous condition.

Most production systems cannot fully do the second one.

The question is not "can we deploy the old version?" The question is "can the old version safely operate against the production state created by the new version?"

That distinction changes how engineers should design releases.

If the new version writes data the old version cannot read, rollback is unsafe. If the new version publishes events the old consumer cannot understand, rollback is incomplete. If the new version calls an external provider and triggers irreversible side effects, rollback is not a reversal. If the new version migrates tenants to a new workflow, rollback may require operational repair, not just deployment repair.

The branch history may look clean.

The deployment platform may support rollback.

The production system may still be moving in only one direction.

Why Code Rollback Is The Easy Case

Code rollback works well when the change is stateless or backward compatible.

Examples:

  • A presentation bug.
  • A performance regression in a pure read path.
  • A bad dependency version that can be replaced.
  • A feature path hidden behind a flag.
  • A deployment with no schema or external side effects.

In those cases, returning to the previous artifact can be reasonable. Kubernetes Deployments support rollout history and rollback mechanics for this class of problem. Blue-green deployments can make traffic rollback a routing decision. AWS deployment configurations can shift traffic gradually or stop rollout when health checks fail.

Those tools are useful.

They are not proof of reversibility.

The tool can move traffic.

It cannot guarantee that the old code understands new data.

It cannot unsend emails.

It cannot uncharge cards.

It cannot reconstruct a queue that was already consumed.

It cannot infer the business meaning of a partially completed workflow.

A rollback button proves only that the platform can attempt to move execution backward. It does not prove that the product, data, and side effects are reversible.

This is where many incident reviews become repetitive. The team had a rollback procedure, but the procedure assumed a simpler system than the one that failed.

Database Changes Break The Illusion

Databases are the most common reason rollbacks fail.

The failure is rarely just "migration failed." The deeper failure is that code and schema were treated as one atomic release when production cannot execute them atomically.

During rollout, old and new application versions may run at the same time. Background workers may lag behind. Replicas may have replication delay. Long-running transactions may span deployment boundaries. Read paths and write paths may not switch together.

Destructive schema changes make rollback fragile:

  • Dropping a column before old code stops reading it.
  • Renaming a column without compatibility.
  • Changing enum values while old workers still emit old values.
  • Tightening constraints before dirty production data is cleaned.
  • Rewriting records into a format the old code cannot parse.

The safer pattern is expand and contract:

  • Add new structure.
  • Make code tolerate old and new shapes.
  • Backfill with monitoring.
  • Switch behavior gradually.
  • Verify.
  • Remove old structure later.

That approach costs more time and discipline.

It buys reversibility.

Without it, rollback becomes a forward-only repair disguised as a backward move.

External Side Effects Do Not Roll Back

Some production actions cannot be undone by redeploying code.

Payments are authorized. Emails are delivered. Webhooks are sent. Inventory is reserved. Contracts are generated. Audit logs are written. Third-party providers receive state transitions. Customers make decisions based on what the system showed them.

This is where rollback becomes business recovery.

The engineering response has to shift from "restore previous artifact" to "repair consequences."

That means designing for:

  • Idempotency.
  • De-duplication.
  • Compensating actions.
  • Outbox patterns.
  • Reconciliation jobs.
  • Provider-state verification.
  • Customer communication.
  • Audit trails.

If a release changes external side effects, the rollback plan should name which effects are reversible, which are compensatable, and which require manual business handling.

Pretending otherwise creates operational debt.

The system may come back up, but the business state remains damaged.

Feature Flags Help Only If They Own The Risk

Feature flags often make rollback faster.

They also create false confidence when they control the wrong boundary.

A flag is useful when it can disable the risky behavior without requiring a new deploy. It is weak when the risky behavior has already mutated state that the old path cannot handle.

Good rollback-oriented flags are placed around decisions:

  • Which engine calculates invoices?
  • Which provider receives writes?
  • Which workflow version processes jobs?
  • Which cohort sees the new behavior?
  • Which dependency path is active?

Weak flags are placed around superficial exposure:

  • Show new UI.
  • Hide button.
  • Enable page.

Those may be fine for product rollout. They may not protect the operational failure mode.

The important question is:

What can this flag stop after production starts changing?

If the answer is only "hide the entry point," the flag is not a complete rollback mechanism.

Observability Decides Whether Rollback Starts In Time

Many rollbacks fail because they start too late.

The team detects the problem after the blast radius has grown. By then, old and new states have mixed, queues have processed work, customers have used the broken path, and downstream systems have accepted bad records.

This is an observability failure.

A rollback strategy needs detection criteria:

  • What metric indicates regression?
  • Which business signal matters?
  • What threshold stops rollout?
  • Who gets paged?
  • What dashboard shows version or cohort impact?
  • What log or trace attribute identifies the release?

DORA's deployment automation guidance emphasizes deployment tests, auditability, and knowing which builds are in which environments. Safe rollback needs the same evidence. You cannot reverse what you cannot identify.

For canary releases, Google SRE material focuses on limiting exposure and using production signals to decide whether to continue. That decision must happen quickly enough to matter.

Rollback is a race between detection and state propagation.

If detection is slow, the rollback path gets worse every minute.

Real-World Trade-Offs

Perfect rollback is not always possible.

Trying to make every change fully reversible can slow delivery, complicate architecture, and increase operational surface area. Temporary compatibility code creates maintenance cost. Feature flags create cleanup burden. Expand-and-contract migrations take more time. Dual writes require careful verification. Compensating actions can be hard to test.

The trade-off is not "rollback everything" versus "rollback nothing."

The trade-off is matching recovery design to failure cost.

For low-risk changes, artifact rollback may be enough.

For data shape changes, compatibility matters more than deployment speed.

For external side effects, compensation and reconciliation matter more than pretending rollback is possible.

For high-volume systems, early detection and progressive rollout matter because even a reversible bug can become expensive at full traffic.

The mature position is risk-based:

  • Design easy rollback where it is cheap.
  • Design forward recovery where rollback is unsafe.
  • Use flags where runtime control changes the outcome.
  • Use canaries where traffic produces meaningful signal.
  • Treat irreversible side effects as business operations, not deploy mechanics.

Rollback is one tool.

Recovery is the real goal.

A Production Story

Production Story

A SaaS team released a new subscription billing flow behind a feature flag. The code path calculated upgrades correctly in staging and passed contract tests against the payment provider sandbox. The rollout started with a small customer cohort. Within an hour, support reported invoices with correct totals but incorrect line-item descriptions.

The team disabled the flag quickly.

That stopped new customers from entering the path. It did not repair the invoices already generated. The old code could not regenerate those invoices because the new flow had written metadata in a shape the old renderer ignored. The payment provider had already received finalized invoice objects.

The rollback worked technically.

The recovery failed operationally.

The team had to reconcile affected invoices manually, issue corrected PDFs, and add a migration to normalize metadata for future rendering. The incident was small because the flag limited exposure, but the rollback was not enough.

The post-incident changes were practical:

  • Invoice metadata became backward compatible across renderer versions.
  • Finalization moved after a validation step comparing API totals and rendered lines.
  • Rollout metrics included "generated invoice requires correction."
  • The feature flag controlled calculation and finalization separately.
  • The recovery runbook included provider-side correction steps.
  • The team added a short-lived reconciliation job for partially processed invoices.

The lesson was not "feature flags failed."

The flag did its job.

The missing design was state recovery after the flag was turned off.

Operational Considerations

Before shipping a meaningful release, ask rollback questions explicitly.

Artifact

  • Can we identify the running version?
  • Can we redeploy the previous artifact?
  • Is the previous artifact still compatible with current configuration?

Data

  • Does the new version write data the old version cannot read?
  • Are migrations backward compatible?
  • Can backfills pause, resume, or roll forward safely?
  • What data repair is needed if rollback happens mid-release?

Runtime

  • Can old and new versions run together?
  • Can traffic be shifted gradually?
  • Can a feature flag stop the risky behavior?
  • What happens to in-flight requests and jobs?

Side Effects

  • What external actions cannot be undone?
  • Are writes idempotent?
  • Are provider calls reconciled?
  • Are compensation steps documented?

Ownership

  • Who can execute the rollback?
  • Who decides when rollback is unsafe?
  • Who owns customer repair?
  • What evidence is preserved for post-incident review?

These questions should be part of release design, not incident improvisation.

Key Takeaways

Further Reading

The Decision Principle

Rollback is not a button.

It is a design property.

If old code cannot read new data, rollback is unsafe.

If external side effects cannot be compensated, rollback is incomplete.

If observability cannot identify release impact quickly, rollback starts too late.

If nobody owns the recovery path, rollback becomes incident improvisation.

The practical standard is simple:

Before production changes, know which parts can move backward, which parts must move forward, and who owns each path under pressure.