What is the saga pattern in microservices?
A sequence of local steps each paired with a compensating action, used to undo a distributed flow that fails partway through.
The saga pattern is a technique for managing a transaction that spans multiple services, each with its own database, when no single commit mechanism covers all of them together. The transaction is broken down into a sequence of local steps, each paired with its own compensating action: if a step partway through the sequence fails, the system does not perform a rollback in the classic sense, which assumes undoing as if nothing had happened, but instead runs the compensations of the steps already completed in reverse order, actions that undo their effects in the real world. The term comes from the paper Sagas by Hector Garcia-Molina and Kenneth Salem, presented at SIGMOD 1987, originally aimed at long-running transactions on the relational databases of the time. In microservices the same idea solves a daily problem: how to keep separate databases per service without giving up a consistent outcome when an order, a payment, and a shipment need to move forward together or unwind together.
See also: Database-per-service · Each microservice owns its own datastore and no other service reads it directly, only through its exposed interfaces.
Orchestration, choreography, and the limit of semantic rollback
A saga can be implemented two ways. In orchestration, a central coordinator knows the whole sequence, calls each service in the planned order, and decides when to trigger compensations: easier to follow and debug, but it introduces a component every service must know about. In choreography, there is no coordinator: each service publishes an event when its own step finishes and reacts to other services' events, a more decoupled architecture that is harder to reconstruct mentally when something goes wrong, because the sequence exists only as the sum of local behaviors. Either way, the same limit applies: a compensation is a semantic rollback, not an undo. A payment can be reversed, an order can be canceled, but an email already sent cannot be made unread, and a shipment already dispatched needs a return, not a clean cancellation. Compensations also need to be designed to be safely repeatable, the same discipline covered in idempotency and backfill, because a retry after a network timeout must not reverse the same payment twice.
A concrete enterprise example
An e-commerce order is handled by three services: payment, inventory, shipping. The payment is authorized, inventory reserves the stock, but shipping fails because the carrier does not cover that postal code. The saga does not leave the system in an ambiguous state: it releases the inventory reservation and refunds the already-authorized payment, in reverse order from how the steps originally ran. None of the three operations was a single ACID transaction spanning all three databases, the guarantees described in ACID still hold only inside each individual service's boundary: the saga is the mechanism that rebuilds a consistent outcome around that boundary, not inside it.
Why it matters for decision makers
The same problem resurfaces, almost unchanged, in agentic workflows: an agent that has already sent an email, issued a purchase order, or opened a ticket with a supplier, and then fails at the next step, has to undo partial actions that have already happened in the real world, not in a database that a query can quietly repair. The uncomfortable point is the same as above: some actions are not compensable, and no amount of software orchestration changes that. Anyone designing these flows should place irreversible actions as late as possible in the sequence, after every step that can still be undone, or put them behind a human approval before the action leaves the system. That is a design decision worth a conversation at project start, because discovering it after the first production incident costs the trust of whoever was supposed to sign off on that approval upstream.
Related terms
- Database-per-service · Each microservice owns its own datastore and no other service reads it directly, only through its exposed interfaces.
- ACID · Atomicity, Consistency, Isolation, Durability: the four guarantees that make a database transaction reliable.
- Idempotency and backfill · An idempotent pipeline produces the same result on rerun, the precondition for a safe backfill over historical data.
- Bounded context · An explicit boundary within which a business term has one coherent meaning, instead of one forced global data model.
- Durable execution · A workflow survives crashes and restarts by resuming from the last saved step, not from the beginning.
If it reminds you of a system nobody dares touch anymore, that is what I put back in order.
SEE SOFTWARE RESCUE