There are two camps when it comes to connecting several services into one flow. One camp puts a central orchestrator in charge, calling inventory, payment, and shipping one after the other. The other camp wants to avoid exactly that central instance and has every service react to events instead. Both sides bring good arguments, and that is what makes the decision hard.
Behind the two camps stand the two base models for connecting multiple services into a flow. Orchestration relies on a controlling instance, choreography on distributed reactions. Which model fits depends far less on taste than on the properties of the concrete flow. Those properties are worth a close look before the decision falls.
Orchestration and choreography are the two base models for connecting multiple API calls into one flow. With API orchestration, a central instance controls the order of calls and knows the whole flow. With choreography, every service reacts to other services' events on its own, and no central instance exists. Orchestration fits flows with a fixed order and strict failure logic, choreography fits loosely coupled, event-driven processes.
Two models for the same problem
Both approaches answer the same question, namely how individual services add up to one coherent business transaction. They give opposite answers as to where the knowledge about the flow lives.
With orchestration, that knowledge sits in one place. An orchestrator knows the steps, their order, and the data handoffs in between. It calls the inventory service, waits for the result, then calls payment, and finally shipping. The participating services know nothing about each other. They answer requests, and that is all. The flow itself is an artifact of its own that can be read, versioned, and changed without touching the services. How such a control layer is built in general is covered in the overview of API orchestration.
With choreography, the knowledge is distributed. There is no place where the flow is written down in full. Instead, the order service publishes an event whenever an order comes in. The inventory service listens for that event and reserves the goods. Once the reservation stands, it publishes an event of its own, which the payment service reacts to. Each service knows only the events that concern it. The overall flow emerges from the interplay of the individual reactions, with no central instance setting the beat.
How the coupling differs
The most visible difference concerns the dependencies between the participants. An orchestrator has to know every service it calls, including its API and failure behavior. The services themselves stay free of any knowledge about the flow. This coupling is visible and concentrated. Read the orchestrator and you see every dependency at a glance.
Choreography turns that around. No service knows the others directly. All of them know only the event channel. A new consumer can listen to an existing event without the sender ever learning about it or needing a change. That loose coupling is choreography’s strongest argument. It carries a flip side that tends to surface late in everyday work, though. The dependencies do not disappear. They turn invisible. Which services react to an event, and what a change to the event schema sets off, is written down nowhere central.
We supported a system in which one seemingly harmless event had collected eleven consumers over the years. When the team wanted to rename a field in the payload, nobody could be found at first who knew all the dependencies. The analysis took longer than the change itself. The coupling had shown up in no diagram beforehand, yet it was there all the same.
The event schema becomes the contract
In a choreography, the event schema plays the same role as the orchestrator’s API in an orchestration. It is the contract everyone relies on. An example shows how much such an event has to carry.
{
"eventType": "order.placed",
"eventId": "b7c2…",
"occurredAt": "2026-06-12T09:14:00Z",
"correlationId": "order-4711",
"payload": {
"orderId": "4711",
"customerId": "8842",
"items": [ { "sku": "A-100", "quantity": 2 } ]
}
}Three fields deserve attention. The correlationId ties all events of one transaction together and is the precondition for reconstructing the overall flow later at all. The eventType with its version reference decides how the schema can evolve without breaking eleven unknown consumers. And the eventId lets consumers detect duplicate deliveries, because most event infrastructures guarantee at-least-once delivery rather than exactly-once.
Retrofit those fields only when the first production incident demands them and you pay far more than with a clean start. That puts choreography’s perceived head start at the beginning into perspective. The central component goes away, and the design effort moves into the event schema and its versioning instead.
Latency, throughput, and operations
In operation, the models differ less dramatically than the debate suggests, yet noticeably in two places. An orchestration usually works with synchronous calls and therefore delivers a definite end to the transaction. The caller learns within one response time whether the order stands. In return, throughput hangs on the slowest participating API, and the orchestrator itself has to be sized for load peaks.
A choreography decouples the load through the event channel. Peaks run into queues, every consumer works at its own pace, and a slow service does not hold the others back. The price is the missing immediate answer. The caller first receives only the confirmation that the request was accepted, and the actual completion comes later. For many transactions that is perfectly fine on the business side, for some it simply is not. That question belongs in the analysis as well, before the model is set.
The path from one model to the other
The reassuring part is that the decision is no one-way street. The most common switch in practice leads from grown choreography to explicit orchestration, and it starts with the same symptom nearly every time. Somewhere, a component appears that watches for stuck transactions. Once you reach that point, the cleanest move is to pull the flow logic into a named orchestrator entirely, because half a control layer combines the downsides of both models.
The reverse path is rarer and easier. Individual steps get carved out of an orchestrated flow and re-attached as event reactions, usually the ones that have nothing to do with the transaction’s success. The orchestrator shrinks and concentrates on the binding core. Both paths work incrementally, and a big-bang rebuild is rarely needed.
Consistency and failure
The comparison gets genuinely interesting at the point of failure. On the happy path, both models work decently. The difference shows when a step fails midway and already completed steps have to be rolled back.
An orchestration has it comparatively easy here. The orchestrator knows the state of the flow and which steps have already succeeded. If shipping fails, it triggers the payment void and the release of the reservation, in exactly that order. The saga pattern, with its compensating actions, can be implemented centrally, because one place holds the overview.
In a choreography, the same logic has to be built distributed. The shipping service publishes a failure event, the payment service reacts with a void, which in turn raises an event the inventory service answers. Every compensation path is an event chain of its own. That works, and it demands considerably more discipline, because the failure path needs the same careful choreography as the success path. In practice, this is exactly the part that gets postponed, and then the first serious outage leaves behind a half-finished state nobody can resolve with confidence.
A choreography without worked-out failure events is riskier in production than an orchestration without compensation, because failure happens distributed and no participant knows the overall state. Choose choreography and the failure paths have to be treated as a first-class part of the design from the start, never as a later add-on.
Observability and the view of the whole
Closely related to the failure question is observability. An orchestrated flow has a natural home where its state is visible. The orchestrator knows which transaction sits at which step, how long it has been waiting there, and what a broken run failed on. Dashboards and reports come almost for free.
A choreography has no such home. The state of a transaction emerges from events spread across several topics and services. To answer where order 4711 currently stands, events have to be correlated, usually through a shared correlation ID and dedicated tracing across the event flow. That is solvable, and mature event architectures have solved it, yet it is work that an orchestration simply does not create. Teams tend to underestimate this item, because it stays invisible during design and only gains weight in operation.
There is a subtler point on top, one that rarely gets said out loud. In a choreography, it is hard to prove that a flow is complete. Whether an event actually triggered every intended reaction is something the system will not show you. An orchestration, by contrast, knows the expectation every run can be checked against.
Speed of change and team boundaries
When it comes to evolving the system, choreography scores. A new team can hang an extra consumer onto an existing event without so much as talking to the sending team. For organizations with many autonomous teams, that is a real speed advantage. Nobody waits for a central body to change the flow.
Orchestration demands coordination at this point. Whoever wants to insert a step into the flow changes the orchestrator, and the orchestrator has an owner to align with. That slows things down, and it also creates a place where the flow gets decided. Whether that is a strength or a weakness depends on how business-critical the transaction is. For a payment process, the deliberate decision in one place is usually welcome. For a notification stream that new consumers dock onto all the time, it would be pure bureaucracy.
The criteria at a glance
These differences condense into a compact decision matrix.
| Criterion | Orchestration | Choreography |
|---|---|---|
| Order | Firmly defined, centrally enforced | Emerges from event reactions |
| Coupling | Visible, concentrated in the orchestrator | Loose, yet invisibly distributed |
| Failure handling | Central compensation, saga in one place | Distributed failure events, high design discipline required |
| Observability | Per-transaction state directly readable | Correlation across events required |
| Speed of change | Alignment with the flow owner | New consumers attach without coordination |
| Typical use | Payment, onboarding, booking | Notifications, data replication, analytics |
The table shows a pattern. Orchestration wins wherever guarantees count, on order, failure handling, and traceability. Choreography wins where independence counts, on coupling and speed of change. There is no winner across all criteria, and that is exactly why both models have coexisted for years.
Which model fits when
The matrix translates into rules of thumb that have held up in projects.
- Orchestration fits when the order is a business requirement, the transaction has a clear end, and a defined state has to be reached on failure. A payment flow, a partner onboarding, or a booking are typical candidates.
- Choreography fits when many consumers react independently to the same occurrence and none of them is responsible for the overall transaction’s success. An order confirmation that mail delivery, statistics, and a recommendation engine react to in parallel is the classic case.
- The number of steps gives a hint. Long chains of five or more dependent steps become hard to follow as choreography, because no single document lets you trace the chain anymore.
- The ownership question helps too. When one specific team has to answer for the overall transaction, that team also needs the control, and that argues for orchestration.
One observation on this keeps repeating itself across years. Teams pick choreography less for the functional properties of the flow than out of wariness toward the central component that sounds like a bottleneck. A few months later they build a component after all, one that watches the event flow, triggers timeouts, and pushes stuck transactions along. That is an orchestrator, it just goes by another name. The reverse happens as well, orchestrators that degenerate into event distributors because nobody truly needs the order. Both malformations appear when the model gets chosen before the flow gets analyzed.
Mixed forms are the norm
The debate often sounds as if an architecture had to commit to one of the two models. Real systems rarely do. They orchestrate the transactions that need hard guarantees and choreograph the streams that need independence, both within the same system.
The order example shows the combination. The core flow of reservation, payment, and shipping is orchestrated, because order and compensation have to be binding. As soon as the order completes, the orchestrator publishes a single event. Mail delivery, statistics, recommendations, and archiving react to that event choreography-style, because none of these consumers influences the core flow. The boundary runs exactly where the guarantees end.
Declarative workflow descriptions have started following the same line. Arazzo, the OpenAPI Initiative’s workflow specification, describes orchestrated flows and, since version 1.1.0, also covers steps that wait on events. The line between the models is getting more permeable in the spec world too. What Arazzo does in general is explained in What is Arazzo, and the event additions are covered in What’s new in Arazzo 1.1.
For a new flow, sort the consumers into two groups first. Whoever participates in the transaction’s success belongs in the orchestrated core. Whoever only wants to be informed attaches via event. That single sorting answers the model question by itself in most cases.
The decision in practice
Back to the two camps from the start. In practice, the resolution usually lands on orchestrating the order process and choreographing the downstream reactions, putting both proposals to work, each where its strengths lie. The discussion gets considerably shorter when the question from the outset reads "which parts of this flow need guarantees and which need independence" rather than "which model is better".
Two related boundary lines round out the picture. How orchestration differs from the API gateway, which often gets mistaken for the same layer, is clarified in API orchestration vs. API gateway. And where the lines to composition and aggregation run is shown in Composition.
Pick a flow in your system that runs over events today and check whether some component already watches timeouts or pushes stuck transactions along. If so, you have found your hidden orchestrator, and it is worth making it explicit.