Orchestration and Choreography Are Not Opposites
They operate at different levels of the same system. Choosing between them is a false dilemma that produces worse architectures than understanding why both exist.
Every serious distributed systems discussion eventually arrives at the same question. Should we orchestrate or choreograph?
The canonical answer is that you should pick one and be consistent. Orchestration advocates argue that explicit control makes systems easier to reason about. Choreography advocates argue that loose coupling makes systems easier to change. Both sides produce blog posts, conference talks, and frameworks supporting their position.
Both sides are arguing about the wrong thing.
Orchestration and choreography are not competing approaches to the same problem. They solve different problems at different levels of a system. Understanding which level you are at — and which pattern belongs there — eliminates an entire class of distributed system complexity that no amount of consistency in your chosen approach will resolve.
What Each Pattern Actually Is
Before the argument, the definitions. They matter because the literature uses both terms loosely and the imprecision causes most of the confusion.
Orchestration is a pattern where one component owns a process. It knows the steps. It initiates each one. It waits for each to complete. It handles the failure. The process starts in this component and ends in this component. Nothing outside of it drives the sequence.
Choreography is a pattern where no single component owns a process. Each component reacts to events published by others. The process emerges from a chain of independent reactions. Nobody is in charge. The outcome is the aggregate of what each participant decided to do when they received their event.
The canonical example for orchestration is a booking flow. Reserve a seat, charge a card, send a confirmation. One service drives that sequence. It waits for each step. If the card charge fails it releases the seat. It is responsible for the outcome.
The canonical example for choreography is an order fulfilment flow in e-commerce. Order placed. Warehouse picks the items. Shipping labels generated. Inventory updated. Customer notified. Nobody drives this sequence — each system reacts to what the previous one published. The outcome emerges.
Both examples are correct. The problem is that most treatments stop there and ask: which of these should your system use?
The Level Problem
Here is the thing neither example acknowledges. Look inside the warehouse picking system in the choreographed e-commerce example. When it receives the order event, it does not just react and emit. It runs a process. Find the items. Check stock levels. Assign to a picker. Print the pick list. Wait for confirmation that the picking is complete. Handle the case where an item is out of stock.
That process — inside the warehouse system — is orchestrated. The warehouse system owns it. It drives the sequence. It handles the failures. It knows when it is done.
The warehouse system participates in a choreographed integration with the rest of the order fulfilment flow. But internally, it runs orchestrations.
These are not in conflict. They are at different levels.
Choreographed integration (the whole)
├── Order service runs OrderPlacementOrchestration
├── Warehouse runs PickingOrchestration
├── Shipping runs LabelGenerationOrchestration
└── Notification service reacts (no internal orchestration needed)
The choreography is the emergent behaviour of the orchestrations reacting to each other's terminal events. The orchestrations are the processes that happen inside each component. You need both. The question was never which to choose — it was always which applies at which level.
The Ownership Test
The clearest way to decide which pattern applies to a given process is the ownership test.
Does this process have a single responsible owner?
If yes — the component that owns the outcome should orchestrate the steps required to reach it. One owner, one process, one set of compensations if something goes wrong.
If no — the process crosses ownership boundaries. No single component can or should drive it. It should emerge from choreography — each component reacting to the facts published by others, each responsible only for its own part.
The booking example from our OpenGym platform makes this concrete. A member booking a class involves checking their membership instrument and confirming the reservation. Reservation owns the outcome — a confirmed or rejected booking. Reservation should orchestrate: check the instrument, request the consume, confirm or reject. One owner, one orchestration, clear compensation paths.
The settlement example is different. When a member attends a class at a partner gym, the platform needs to record the attendance, calculate what one gym owes the other, initiate the payment, confirm settlement, and escalate if it fails. Who owns this outcome? Not Attendance — it just recorded a fact. Not Platform Billing — it calculated the obligation but does not initiate payments. Not Finance — it processes payments but is not responsible for the settlement relationship.
Nobody owns it. The outcome emerges from each component reacting to the previous one's event. That is choreography. Trying to give one component ownership of this process would require it to know about every other component involved — creating exactly the coupling that choreography is designed to avoid.
Why the Binary Choice Produces Bad Architectures
The "orchestrate everything" school produces systems where one service becomes the coordinator for flows it does not own. The booking service ends up knowing about inventory, shipping, and notification. Every new downstream consumer requires a change to the orchestrator. The coupling that was supposed to be explicit becomes a maintenance burden.
The "choreograph everything" school produces systems where processes that genuinely have a single owner are fragmented across multiple reactive components. The booking flow — which should be simple to reason about — becomes a chain of events where debugging a failed booking requires reconstructing the sequence from logs across five services.
The correct answer is local: orchestrate processes that have a single owner, choreograph integration across ownership boundaries. Every system needs both. The architecture that uses only one is optimised for the style rather than for the structure of the problem.
The Nesting Point
There is a third insight that the binary framing makes invisible.
A choreographed integration is composed of orchestrated processes. The choreography is the top level — the big picture of how components react to each other across the whole system. The orchestrations are the bottom level — the detailed sequences that happen inside each component when they receive an event.
Between these two levels, there is a middle level that is often overlooked: the integration chain.
When Reservation's booking orchestration terminates with a ReservationConfirmed event, it triggers downstream processes in Tenant Billing, Attendance, and Notifications. Those processes are owned by their respective components. Reservation does not wait for them. Reservation does not know what they do. But they are all part of the same business transaction — a member successfully booked a class.
Business transaction: Member Books a Class
BookingOrchestration ← Reservation owns this
NESTED: InstrumentConsumeProcess ← Entitlement owns this, control returns
TERMINAL: ReservationConfirmed
│
├── DOWNSTREAM: BillingRecordProcess ← Tenant Billing owns this
├── DOWNSTREAM: AttendancePendingProcess ← Attendance owns this
└── DOWNSTREAM: NotificationProcess ← Notifications owns this
The NESTED relationship is synchronous within the orchestration — Reservation waits for Entitlement to confirm the consume before it can confirm the booking. The DOWNSTREAM relationships are asynchronous — Reservation does not wait, does not know, does not care. Each downstream component owns its own process.
This three-level structure — orchestration within a component, nested processes that must complete before the orchestration can advance, downstream processes triggered by the terminal event — is the complete picture. Most systems have all three levels. Most architecture discussions acknowledge only the top and the bottom.
The Practical Implications
When designing a new process, ask the ownership question first. If you cannot name a single component that owns the outcome, the process should be choreographed. If you can name one, that component should orchestrate.
When a nested process is required — when your orchestration cannot advance until another component responds — make that explicit. The component that is required to respond is a participant in your orchestration. The event that carries the request and the event that carries the response are a correlated pair. Name them. Document them. Monitor them. A nested process that times out is a different operational problem from a downstream process that never starts.
When a downstream process is triggered by your terminal event — you are done. Your responsibility ended when you published your terminal event. The downstream process is owned by someone else. Do not reach into it. Do not coordinate it. Trust the event contract and let the downstream component do its job.
Design your saga coordinator to observe, not to drive. The saga coordinator — the platform-level component that watches cross-cutting flows — should surface anomalies, not manage sequences. If it is making decisions about what happens next in a choreographed flow, it has become an orchestrator in disguise, and you have re-introduced the coupling you were trying to avoid.
The Claim
Orchestration and choreography are different levels of the same system. Every distributed system that processes real business transactions needs both. The processes inside each component are orchestrated by that component. The integration across component boundaries emerges from choreography. The integration chain — the nested processes and downstream triggers that together constitute a business transaction — is where the two levels connect.
Choosing between orchestration and choreography is not an architectural decision. Knowing where each applies is.
This post is part of a series on building modern distributed systems, written around a worked example — a fitness platform called OpenGym built from first principles. The source material, event contracts, and capability specifications are available as an open reference implementation.