Choreography vs Orchestration in Event-Driven Integration
Concept
When multiple systems need to react to a single business process — an order being placed, a booking being confirmed — there are two fundamentally different ways to wire them together via events, and the choice shapes coupling, debuggability, and failure behavior for the life of the integration.
Choreography has no central controller: each service independently subscribes to the events it cares about, does its work, and emits its own events in turn, which other services may react to. A booking_confirmed event might be independently consumed by a notifications service, a billing service, and a partner-sync service, none of which know the others exist. Services are coupled only to the event bus and to the shape of the events they consume/produce — a new service can start reacting to an existing event without any existing service being modified or even aware of it. This is the pattern behind an event bus like AWS EventBridge or Google Cloud Pub/Sub used for many-to-many routing: publishers don't know or care who's listening.
Orchestration puts a central coordinator (a workflow engine, an orchestrator service) in charge of the sequence: it explicitly calls each participating service in order, tracks the state of the overall process, and decides what happens next based on each step's result. The order-processing service in an orchestrated design knows it needs to call billing, then inventory, then shipping, and in what order — the orchestrator holds the full picture of the business process; no individual participant needs to.
Tradeoffs
| Approach | Benefit | Cost |
|---|---|---|
| Choreography | Loose coupling — services depend only on event shapes, not on each other's existence; easy to add a new consumer without touching existing services | The end-to-end flow of a single business process is not visible anywhere in the code — tracing "what happened to this order" requires distributed tracing across every service that touched it; at scale, can degenerate into "event spaghetti" — a tangled web of implicit dependencies that's hard to reason about or safely change |
| Orchestration | Full process state is visible in one place — retries, timeouts, and the current status of any given process are trivial to query and debug from the orchestrator | The orchestrator becomes tightly coupled to every participant's API (it must know how to call each one) and is a potential single point of failure — if it goes down, every in-flight process it manages stalls |
| Point-to-point integration (direct API calls) | Simplest possible wiring for exactly two systems, lowest initial setup cost | Doesn't scale past a handful of integrations — each new consumer needs its own bespoke connection, and adapting one connection for a new use case is costly since it wasn't built for reuse |
| Event bus with filtering/routing rules (e.g. EventBridge rules, Pub/Sub topic filters) | Many-to-many routing without every producer/consumer pair needing custom code; new consumers plug in by subscribing, not by the producer changing | Requires schema discipline across all producers/consumers (see the tracking-plan discipline that applies equally to internal event schemas) — an ungoverned schema drifts the same way an undocumented API does |
When to use / when not to
- Reach for choreography when the participating services genuinely don't need to know about each other's existence and the "did this whole process succeed" question isn't something anyone needs to answer in real time — e.g. fan-out side effects like notifications, analytics, and audit logging off a single domain event.
- Reach for orchestration when a business process has to be tracked as a first-class entity with a queryable status (pending / in-progress / failed / completed) and needs coordinated retry/compensation logic across steps — a multi-step payment or fulfillment workflow where "where exactly did this order get stuck" has to be answerable without piecing together five services' logs.
- A hybrid is common and often correct: choreograph the loosely coupled side effects of a domain event, but orchestrate the core transactional workflow that has real steps, real failure modes, and a real need for a status query. Don't force one pattern uniformly across a whole system when different parts of it have genuinely different coordination needs.
- Avoid choreography for a process where an operator will need to answer "what's the current state of order #12345" under time pressure (e.g. a support escalation) — without an orchestrator or an explicitly built read-model tracking state, that answer requires assembling logs from every participating service after the fact.
- Don't default to point-to-point integration once there are more than two or three systems reacting to the same trigger — that's exactly the case an event bus with many-to-many routing (EventBridge, Pub/Sub) is built for, and retrofitting a point-to-point mesh into a bus later means rewriting every existing connection.
Common pitfall
Choosing choreography for its loose-coupling appeal without budgeting for the debugging cost up front, then discovering during a live incident that no single place shows the status of an in-flight business process — reconstructing "what happened to order #12345" requires correlating logs across every service the event chain touched, using whatever request/trace ID discipline (or lack of it) happens to exist. This is the exact failure mode both AWS's and independent EDA writeups flag as "event spaghetti" at scale: coupling was avoided, but observability was never built to compensate, so the system is technically decoupled and operationally opaque at the same time. The fix isn't abandoning choreography — it's pairing it with distributed tracing and a durable event log (so any process's history can be replayed) from the start, not bolted on after the first hard-to-debug incident.
Engineering Lens
The real design question isn't "event bus vs API calls" in the abstract — it's whether anyone needs to answer "what is the current state of this specific business process" under time pressure, and if so, who is responsible for tracking that state. Choreography that has no answer to that question isn't a smaller version of orchestration, it's a different tradeoff entirely: coupling cost traded for observability cost. A design review answer worth trusting names which specific processes are choreographed vs orchestrated and why, rather than a single blanket architectural stance applied everywhere regardless of whether that process actually needs a tracked, queryable status.
Sources
- Orchestration vs. Choreography — Key Differences In Implementing Service Orchestration vs. Choreography — AWS Community
- Amazon EventBridge FAQs — Amazon Web Services
- Event-Driven Architecture with Pub/Sub — Google Cloud