Orchestration vs Choreography
Choosing between a central coordinator that commands services and a decentralized model where services react to domain events.
What it is
Orchestration uses a central coordinator — an orchestrator — that explicitly commands each participating service in sequence or in parallel, waits for responses, and decides the next step. The orchestrator holds the full business process flow; individual services are ignorant of the larger workflow and only know how to execute their specific task when commanded. Implementations include BPMN workflow engines (Camunda, Flowable), dedicated workflow services (AWS Step Functions, Temporal, Conductor), or a purpose-built saga orchestrator service.
Choreography distributes coordination logic across services: each service listens for domain events published by other services, reacts by performing its own work, and publishes new events that downstream services respond to. No single service knows the full workflow; the overall process emerges from the interactions of many independent services reacting to events. A Kafka topic becomes the shared communication channel; services subscribe to relevant topics and publish results to other topics. The Saga pattern can be implemented via either style.
Why it exists
In a monolith, multi-step business processes are implemented as in-process method calls — coordination is trivial because everything shares a transaction. In microservices, distributed transactions are expensive and fragile, so long-running business processes must be decomposed into a series of compensatable local transactions. The choice between orchestration and choreography determines where the process knowledge lives: centrally in an orchestrator, or distributed across services via shared event contracts.
Neither approach is universally superior. Orchestration provides operational clarity — you can visualize the state of any workflow instance in the orchestrator's UI, retry failed steps, and compensate from a single place. Choreography provides better team autonomy — each service team can deploy independently without coordinating with a central workflow team. The observable tendency is that simple, linear flows favor orchestration; complex, evolving event-driven architectures favor choreography.
When to use
- Use Orchestration when: the business process has many steps with complex branching, timeouts, and compensation logic that would be hard to reason about if distributed across services.
- Use Orchestration when: you need workflow-level observability — the ability to query "what is the current state of order #12345's fulfillment process?" and see a visual flow diagram.
- Use Orchestration when: there is a single team owning the entire business process and the orchestrator represents a sensible aggregation of responsibility.
- Use Choreography when: different teams own different services and you want each team to deploy independently without coordinating with a central workflow team.
- Use Choreography when: the event model is already established (Kafka is the backbone) and services naturally publish domain events as part of their normal operation.
- Use Choreography when: new consumers can be added to react to existing events without modifying any existing service (open/closed principle for workflows).
When not to use
- Don't use a choreography approach for workflows with hard, complex compensation requirements (e.g., rollback 8 services in a specific order) — the lack of a central view makes debugging failures extremely difficult.
- Don't use orchestration with a "smart orchestrator" that contains domain logic beyond flow control — this recreates the ESB "god object" antipattern at the workflow level.
- Don't apply orchestration to simple event-driven use cases (a user signs up → send welcome email) where the extra machinery adds overhead with no benefit.
- Don't use choreography when services become tightly coupled through shared event schemas that change frequently — the distributed coupling is harder to manage than central orchestration.
Typical architecture
ORCHESTRATION (Temporal / Step Functions):
┌─────────────────────────────────────────┐
│ Order Fulfillment Orchestrator │
│ 1. PaymentService.charge() ──────────▶│ PaymentService
│ 2. InventoryService.reserve() ────────▶│ InventoryService
│ 3. ShippingService.schedule() ────────▶│ ShippingService
│ 4. NotificationService.send() ────────▶│ NotificationService
│ (on fail: compensate in reverse order) │
└─────────────────────────────────────────┘
CHOREOGRAPHY (Kafka events):
OrderService
│ publishes: OrderPlaced
▼
Kafka ──▶ PaymentService
│ publishes: PaymentCompleted
▼
Kafka ──▶ InventoryService
│ publishes: InventoryReserved
▼
Kafka ──▶ ShippingService
│ publishes: ShipmentScheduled
▼
Kafka ──▶ NotificationService
Pros and cons
Orchestration Pros
- Centralized visibility: workflow state, history, and progress are queryable from one place.
- Explicit compensation: the orchestrator owns rollback logic, making failure handling consistent and testable.
- Timeout management built in: orchestrators can pause, wait for external events, and resume after days or weeks.
- Easier to understand by new team members — the flow is explicit in code or a visual diagram.
- Simpler debugging: failures are recorded in the workflow history with inputs, outputs, and error messages per step.
Choreography Pros / Orchestration Cons
- Choreography enables team autonomy: services can be developed and deployed without coordinating with a central workflow team.
- Choreography scales independently: each service scales based on its own event consumption rate, without a central bottleneck.
- Adding new consumers to existing events requires no changes to existing services (open/closed principle).
- Orchestration creates a central coupling point; if the orchestrator service is down, no workflows can progress.
- Orchestrators can accumulate workflow logic that should live in domain services, becoming a new form of monolithic logic.
Implementation notes
For orchestration, Temporal is the leading open-source workflow orchestration platform. Workflows are written as code (Go, Java, Python, TypeScript) with durable execution — Temporal replays the workflow from a deterministic event history after failures, so in-progress workflows survive process restarts and infrastructure outages. Avoid putting I/O directly in workflow code; wrap all external calls in Activities (which Temporal schedules with retry policies). AWS Step Functions provides a managed alternative using JSON-defined state machines with native AWS service integrations.
For choreography, establish clear event schema contracts using Avro or Protobuf with a schema registry to prevent consumers from breaking when events evolve. Use consumer groups to allow multiple services to independently consume the same event stream. Implement correlation IDs on all events so distributed traces can reconstruct the full end-to-end flow across services. Build a "saga audit" read model — a projection that consumes all relevant events and reconstructs the current state of each business transaction — to provide the operational visibility that choreography otherwise lacks.
Common failure modes
- Choreography spaghetti: As the number of services grows, event chains become impossible to follow; no one can explain the full flow of a business process without tracing through 10 different service codebases.
- Orchestrator becomes a bottleneck: A single orchestrator service handles all workflows and becomes a performance or availability bottleneck as traffic grows.
- Missing compensation in choreography: PaymentService charged the customer but InventoryService failed to reserve; without a central coordinator, no one is responsible for initiating a refund.
- Non-deterministic workflow code: A Temporal workflow uses
Date.now()or a random number generator directly; replay produces different results, causing Temporal to throw non-determinism errors. - Event versioning breaks choreography: PaymentService adds a required field to
PaymentCompleted; InventoryService's consumer fails to deserialize the new version and stops processing, silently halting all order fulfillment.
Decision checklist
- Is this a linear, well-defined process (favors orchestration) or an open-ended, evolving event-driven interaction (favors choreography)?
- Is operational visibility (current state of each in-flight instance) a critical requirement?
- Do you have long-running workflows that span days or weeks (favors orchestration with durable execution)?
- Do independent teams own different services in the workflow, and do they need deployment autonomy (favors choreography)?
- Have you designed explicit compensation for failure scenarios in either approach?
- Can you build a saga audit read model for choreography to provide end-to-end visibility?
Example use cases
- E-commerce order fulfillment (Orchestration): An order fulfillment workflow in Temporal coordinates payment, inventory reservation, shipping scheduling, and notification with retry policies on each step and explicit compensation (refund + inventory release) on failure.
- Account registration (Choreography): A user registers; UserService publishes
UserRegistered; EmailService sends a welcome email; CRMService creates a lead; AnalyticsService records the event. Each service independently reacts — new integrations can be added without touching UserService. - Insurance claims processing (Orchestration): A claims workflow in Step Functions routes a submitted claim through fraud detection, coverage verification, adjudication, and payment, with human review tasks using Step Functions Wait for Callback tokens.
Related patterns
- Saga Pattern — The pattern for managing distributed transactions via either orchestration or choreography.
- Event-Driven Architecture — The foundation for choreography-based workflows.
- Enterprise Service Bus — The classic orchestration hub; understand why modern architectures moved away from it.