Architectural · Service Comms · DWG NO. 051

Choreography vs. Orchestration

Two opposite ways to coordinate a multi-service workflow — a central controller calling each step, or services independently reacting to each other's events.

TypeService Communication
ScopeMulti-step workflow coordination
ComplexityMedium
Common inOrder processing, distributed sagas, workflow engines

Coordination has to live somewhere — the question is where

A multi-step workflow across services needs its sequence and error-handling defined somewhere. Put it in one place and that place becomes a single dependency everything relies on. Spread it across services reacting to each other's events, and the sequence becomes implicit, readable only by tracing many services' event handlers.

Orchestration centralizes; choreography distributes

Orchestration (see the dedicated Orchestration page) has one coordinator directly calling each service in sequence and deciding what happens next. Choreography (see the Saga page) has each service publish an event when it finishes, and other services independently subscribe and react — there is no central coordinator at all.

OrchestrationCoordinatorABCChoreographyAeventBeventC

The same workflow, coordinated both ways

Same two steps, two coordination styles: one function explicitly sequences them; the other lets each step trigger the next through an event.

choreography-vs-orchestration.js
// Orchestration: one coordinator calls each step directly.
async function orchestratedCheckout() {
  await reserveInventory();
  await chargePayment();
  console.log("orchestrated: checkout complete");
}

// Choreography: each step reacts to an event, no central coordinator.
const bus = new EventTarget();
bus.addEventListener("InventoryReserved", async () => {
  await chargePayment();
  bus.dispatchEvent(new Event("PaymentCharged"));
});
bus.addEventListener("PaymentCharged", () => console.log("choreographed: checkout complete"));

async function reserveInventory() { console.log("inventory reserved"); }
async function chargePayment() { console.log("payment charged"); }

await orchestratedCheckout();
bus.dispatchEvent(new Event("InventoryReserved")); // kicks off the choreographed chain

Trade-offs