🧭 Analogy
Tweeting “I’m hungry” is an event: a broadcast fact you’re happy for the world to ignore. Emailing a specific restaurant to order dinner is a command: clear intent aimed at one recipient who cannot pretend it never arrived. Same person, same hunger — completely different communication semantics. Distributed systems make the same choice on every link.
Two precise definitions
Ruecker insists on tight definitions to cut through the fog:
- Orchestration = command-driven communication. A component coordinates others by sending commands. A command is a message where A wants B to do something; B cannot simply ignore it (it may reject or acknowledge). Crucially, orchestration is not limited to workflow engines — any component sending a command is orchestrating.
- Choreography = event-driven communication. Components react to events. An event is something that happened — a fact about the past. The defining trait: the emitter does not know who reacts or why, and does not care.
A common source of confusion is mixing up semantics with transport. A message is just the envelope; “event” and “command” describe the meaning of the payload. A command can travel asynchronously over a queue; an event can travel over a REST feed. So “commands are synchronous” and “Kafka can’t do commands” are both myths — a command can be written as a Kafka record.
The choice is per link, not global
flowchart LR subgraph Choreography["Choreography (events)"] CO["Checkout"] -->|"order placed (event)"| PAY["Payment"] PAY -->|"payment received (event)"| INV["Inventory"] end subgraph Orchestration["Orchestration (commands)"] OF["Order fulfillment<br/>(owns the outcome)"] -->|"retrieve payment (command)"| P2["Payment"] OF -->|"fetch goods (command)"| I2["Inventory"] end
Calling a whole system “choreographed” is usually a meaningless oversimplification — good architectures mix both and decide on each individual link. The deciding question is direction of dependency: every communication couples two services, and you only choose which side carries the unavoidable domain coupling. With events, the receiver depends on the sender; with commands, the sender depends on the receiver.
Map responsibility first:
- If the sender cares that something happens (a legally required welcome letter must go out) → command.
- If the sender does not care but a receiver owns the outcome (a loyalty service enrols new customers off an event) → event.
The more general and reusable a downstream component is — a payment service used by many callers — the more it should expose a command API, so it need not change every time a new caller appears.
graph TD
L["A communication link"] --> Q{"Does the sender care it happens?"}
Q -->|"yes, needs the outcome"| CMD["Send a command<br/>sender coupled to receiver"]
Q -->|"no, receiver owns it"| EVT["Emit an event<br/>receiver coupled to sender"]
CMD --> O["Orchestration"]
EVT --> C["Choreography"]The event-chain trap
Event chains hide the process
Wiring checkout → payment → inventory purely through event subscriptions implements a business process, but the subscriptions aren’t really independent: you need payment before shipping. There is no place to understand or control the sequence and no owner of end-to-end fulfilment or its SLA. Reorder two steps and three teams must change and coordinate a deployment — a distributed monolith.
The fix is to give the process a home: a dedicated order fulfillment service that may subscribe to an “order placed” event but then commands payment and inventory in the order it controls. Now one team owns the outcome, the sequence lives in one place, and you gain end-to-end visibility.
Debunking 'choreography is more decoupled'
Take a realistic change — add a “criminal check” — and count the services that must change. Often it’s the same number in both styles, because every link couples something. Choreography merely moves the coupling to the receiver; orchestration additionally gives you a single place for visibility and control.
Workflow engines serve both
A workflow engine is not “the orchestration tool” only. It can subscribe to events, wait with timeouts (wait for two events within a time frame, act if one never arrives), and issue commands — all inside one model. And “orchestration” need not be central: use local or distributed orchestration, with the engine living inside the service that owns the process.
Watch for commands in disguise
A “Customer Needs To Be Sent A Notification Event” that exactly one service must act on is a command wearing an event costume. Name it “Send Notification” and model it as a command — clarity beats dogma.
See also
- Why long-running processes are hard — state, time, and failure across boundaries.
- Where workflow engines fit — running engines decentrally without a central spider.
- Integrating with services and APIs — sync vs async, correlation, and idempotency.
When to use it — and when not
✅ Reach for it when
- Deciding, per communication link, whether a sender commands or a receiver reacts
- An end-to-end flow needs a clear owner accountable for the outcome and its SLA
- Event chains have grown into an implicit process nobody can see or change safely
⛔ Think twice when
- Treating 'orchestration' as a synonym for 'centralized god service' (it is not)
- Forcing everything to be an event because a broker is fashionable
- Assuming choreography is automatically more decoupled — every link couples something
Related topics
The moment your logic crosses a boundary it becomes long-running — and you inherit state, time, and failure problems that a workflow engine exists to solve.
auto-foundationsWhere Workflow Engines FitA workflow engine is a persistent, scheduling state machine — run it as a service, keep it decentralized, and judge its adoption by return on investment.
auto-operatingIntegrating with Services and APIsOrchestrate anything with an API — and respect boundaries: synchronous or async calls, correlation, and clean result-only APIs instead of the hot-potato anti-pattern.
Check your understanding
Score: 0 / 41. What is the precise difference between orchestration and choreography?
The distinction is semantic, not protocol- or topology-based. A component sending a command orchestrates; components reacting to events choreograph. Both can run over REST or messaging, locally or distributed.
2. What is the litmus test for whether a message is an event or a command?
An event is a fact about the past that the emitter doesn't care who consumes; a command expresses intent the recipient cannot simply ignore.
3. With events versus commands, which way does the domain coupling point?
Every link couples two services; you only choose which side carries the unavoidable domain coupling. That is the core of the link-by-link decision.
4. What is the main risk of implementing a business process as an event chain?
An event chain scatters a logical flow across independent subscriptions. Reordering steps may force several services to change and deploy together — a distributed monolith with no single place to understand the process.
Comments
Sign in with GitHub to join the discussion.