Explainstuff.mebeta
All concepts
Cloud Native Patternsadvanced6 min

Compensating Transaction

Undo a multi-step operation not by rewinding it, but by running new steps that counteract what already happened.

You book a holiday: flight, hotel, rental car — three separate bookings made one after another. The flight and hotel go through, but the car company has nothing available. You can't "rewind time" to before you booked the flight; that booking really happened. What you can do is cancel the flight and the hotel — new actions that undo the earlier ones. That's a compensating transaction.

The problem

Inside a single database, undo is easy: an ACID transaction either commits everything or rolls it all back, and a failed step vanishes as if it never ran. But a business operation that spans multiple services or databases can't be wrapped in one transaction. Each step commits to its own store the moment it succeeds. So when step three fails, steps one and two are already durably committed — there's no shared transaction manager to roll them back as a unit. You're left holding partial, real, irreversible-by-default progress.

Before — partial progress with no way back
each step commits to its own service
Book Flight · committed
Book Hotel · committed
Book Car · fails
No shared rollback
Flight and hotel commit independently, then the car booking fails. With no shared transaction spanning the services, nothing rolls the first two back — you're left holding durable, half-finished state.

How it works

For every step that changes state, you define a paired compensating step that semantically reverses it: charge payment pairs with refund payment, reserve stock pairs with release stock, book flight pairs with cancel flight. When a later step fails, you walk backward through the steps that already succeeded and run each one's compensation in turn. Crucially, this is not a database rollback — a refund is a brand-new transaction that offsets the original charge; the charge still exists in history. It's a logical undo built from forward actions. The diagram below shows a forward chain committing step by step, a failure on the last step, and the compensations firing in reverse to unwind the completed work.

Undo by counteracting, not rewinding
forward step / compensation
Book Flight
Book Hotel
Book Car
Cancel Flight
Cancel Hotel
The car booking fails, so compensations run in reverse — cancel hotel, cancel flight — unwinding the work that already committed.
Tip

Make compensations idempotent and retryable. A compensation can itself fail mid-flight, or get triggered twice after a crash. If "refund payment" runs twice it must not refund twice. Lean on idempotency keys and a retry policy so unwinding is as robust as the forward path — an undo that breaks halfway is worse than no undo at all.

When to use it

Compensating transactions are the undo half of a saga: use them whenever a multi-step operation spans services that can't share one ACID transaction and you still need a way to back out of partial progress. They fit long-running workflows — order fulfillment, travel booking, provisioning — where each step is independently committed and any step might fail.

The hard part is that not everything is cleanly reversible. An email already sent or a physical package already dispatched can't simply be cancelled, so some compensations must be approximate (a follow-up correction), a fallback, or a hand-off to a human. If your operation lives in a single database, don't bother — let a plain ACID rollback do the work for free.

Key takeaways

  • A compensating transaction undoes the effect of an already-committed step by running a new, counteracting action — not by rolling a database back.
  • It's needed when work spans services that can't share one ACID transaction, so each step commits independently.
  • Compensation is semantic 'undo': a refund offsets a charge, it doesn't erase it.
  • Compensating steps must be idempotent and retryable, because they can fail or run more than once.
  • Some effects can't be fully reversed — design for forgiveness, fallbacks, or human intervention.

Keep going