Event-Driven Architecture Vocabulary: Event Storming, CQRS, Saga Pattern, and More
A complete guide to event-driven architecture vocabulary: domain events, event sourcing, CQRS, saga patterns, choreography vs. orchestration, schema registry, and CloudEvents. For backend engineers, system architects, and developers building distributed event-driven systems.
Event-driven architecture (EDA) is a fundamental design pattern for modern distributed systems — used in microservices, real-time pipelines, and enterprise integration. Yet its vocabulary is dense: domain events, commands, sagas, choreography, CQRS, event sourcing, schema evolution.
If you join an engineering team working with Kafka, RabbitMQ, EventBridge, or any event-driven system, you need to speak this vocabulary precisely. This guide covers the 45 terms that matter most.
What Is Event-Driven Architecture?
Event-Driven Architecture (EDA) is a design pattern where components communicate by producing and consuming events — notifications that something has happened — rather than calling each other directly.
Key properties:
- Loose coupling — producers don’t know who consumes their events
- Asynchronous — the producer doesn’t wait for the consumer to finish
- Scalable — consumers can scale independently of producers
“We moved from synchronous REST calls between microservices to an event-driven architecture — now the payment service just emits a
PaymentCompletedevent and doesn’t need to know about inventory, shipping, or loyalty points.”
Core Vocabulary: Events, Commands, Messages
Domain Event
A domain event is a record that something significant happened in the business domain. Events are named in the past tense and describe a fact, not a request.
Good event names: OrderPlaced, PaymentFailed, UserRegistered, InventoryDepleted
Bad event names: PlaceOrder, ProcessPayment ← those are commands, not events
“We emit an
OrderShippeddomain event when the warehouse confirms dispatch — downstream systems (notifications, analytics, loyalty) react to it independently.”
Command
A command is a message that tells a service to do something. Commands are named in the imperative: PlaceOrder, SendEmail, ProcessRefund. A command may or may not be accepted — it can be rejected.
Key difference from events:
- Event: “X happened” — past tense, fact, cannot be undone
- Command: “Please do X” — imperative, request, may fail or be rejected
Message
A message is the general term for any data sent between systems — may be an event, a command, or a query result. Events and commands are specialised types of messages.
Event Envelope / Event Envelope Pattern
An event envelope wraps the event payload with metadata: event ID, event type, timestamp, source service, schema version. Separating metadata from payload makes routing and logging easier.
Typical envelope:
{
"id": "evt_9823hf",
"type": "order.placed",
"source": "order-service",
"time": "2026-04-08T10:00:00Z",
"data": { "orderId": "123", "amount": 99.99 }
}
CloudEvents Specification
CloudEvents is a CNCF specification for describing event data in a common, vendor-neutral format. Defines a standard set of envelope attributes: id, source, type, datacontenttype, time etc.
“We standardised on CloudEvents so our event consumers don’t need custom parsing for every producer — the envelope is always the same format.”
Event Storming
Event Storming
Event storming is a collaborative workshop technique (invented by Alberto Brandolini) where a cross-functional team maps out a business process by placing coloured sticky notes on a wall:
- 🟠 Orange: domain events
- 🔵 Blue: commands
- 🟡 Yellow: actors (who triggers the command)
- 🟣 Purple: policies / business rules (when X event → trigger Y command)
- 🟩 Green: external systems
- 🔷 Cyan: read models (views/queries the system needs)
“Before writing any code, we ran a two-day event storming workshop with the product owner, domain experts, and engineers — we discovered 30 domain events we hadn’t considered and found where our bounded contexts should be.”
Aggregate
In event storming and Domain-Driven Design, an aggregate is a cluster of related entities treated as a single unit for data changes. Events are typically emitted by aggregates.
Policy
In event storming, a policy (shown in purple) represents a business rule that reacts to an event and triggers a command: “When [domain event] then [command]”.
Example: “When OrderPlaced then ReserveInventory”
Read Model
A read model is a specialised, pre-computed data view optimised for queries — distinct from the write model. In CQRS and event sourcing, read models are built by consuming events.
Event Sourcing
Event Sourcing
Event sourcing is a persistence pattern where the state of an entity is derived by replaying a sequence of events, rather than storing the current state directly.
Instead of:
UPDATE orders SET status = 'shipped' WHERE id = 123;
You store:
Event: OrderPlaced → timestamp: 10:00
Event: PaymentTaken → timestamp: 10:05
Event: OrderShipped → timestamp: 14:00
The current state is computed by replaying all events from the beginning.
“We use event sourcing for the order aggregate — we can reconstruct the exact state of any order at any point in time by replaying its event history.”
Event Store
An event store is a database purpose-built for storing events in append-only fashion. Unlike a regular database, you never update or delete events — you only append new ones. EventStoreDB, Apache Kafka (as a durable log), and custom implementations are common.
Projection
A projection (or event projection) is a process that consumes events from the event store and builds a read model. Projections can be rebuilt by replaying all events from the beginning.
“Our analytics dashboard is a projection — it consumes all
OrderPlacedandPaymentCompletedevents and builds aggregated sales statistics.”
Event Replay
Event replay is applying all stored events from the beginning to rebuild state or projections. Used after bugs are fixed, for new projections, or for migrations.
CQRS (Command Query Responsibility Segregation)
CQRS
Command Query Responsibility Segregation (CQRS) is a pattern that separates the write model (commands that change state) from the read model (queries that return state). Often combined with event sourcing.
- Command side: handles state changes, emits events
- Query side: builds optimised read models from events
“Our product catalogue uses CQRS — the write side handles complex inventory updates and emits events; the read side maintains a denormalised ElasticSearch index optimised for search.”
Command Bus
A command bus is a component that routes commands to their handlers. Commands go in, one handler processes each command, and optionally an event is emitted as a result.
Eventual Consistency
Eventual consistency means that after a command is processed and an event is emitted, the read model will be updated eventually — not immediately. There is a brief window where the write model and read model are out of sync.
“After a user updates their profile, the read model updates within 50–200ms — it’s eventually consistent. We show the user their updated data immediately from the write model to avoid confusion.”
Saga Pattern
Saga
A saga is a pattern for managing long-running transactions across multiple services — where each step is a local transaction and each failure has a compensating transaction to undo it.
Sagas replace distributed ACID transactions (which are often unavailable across microservices) with a sequence of loosely coupled steps.
Choreography-Based Saga
In a choreography saga, each service reacts to events emitted by the previous service. There is no central coordinator — services are autonomous and react to the event stream.
Flow example — Order Saga (choreography):
OrderService → emits OrderCreated
→ PaymentService reacts → emits PaymentProcessed
→ InventoryService reacts → emits InventoryReserved
→ ShippingService reacts → emits OrderShipped
Pros: loose coupling, no single point of failure
Cons: hard to track the global saga state, debugging is complex
Orchestration-Based Saga
In an orchestration saga, a central saga orchestrator sends commands to each service and waits for responses / events before proceeding to the next step.
Flow example (orchestration):
SagaOrchestrator → commands PaymentService
SagaOrchestrator ← receives PaymentCompleted
SagaOrchestrator → commands InventoryService
...
Pros: easy to see global saga state, simpler debugging
Cons: the orchestrator is a single point of coupling
“We chose orchestration over choreography because our order saga has 8 steps and conditional branches — the explicit orchestrator makes the flow understandable and testable.”
Compensating Transaction
A compensating transaction is the undo operation for a saga step — run when a later step in the saga fails. Each step in a saga must have a compensating transaction.
Example: If ShipOrder fails after ChargePayment succeeded, the compensating transaction is RefundPayment.
Dead Letter Queue (DLQ)
A dead letter queue is where messages go when they cannot be processed — after repeated failures, poison messages, schema mismatches, or expired TTLs. Essential for diagnosing and recovering failed event processing.
Message Brokers
Topic
In Kafka and similar systems, a topic is a named, persist log of events. Producers write to topics; consumers read from them. Topics are the primary organisational unit.
Partition
A Kafka partition is a subdivision of a topic. Messages in a partition are ordered. Partitions enable parallelism — multiple consumers can process different partitions simultaneously.
“The
orderstopic has 50 partitions — our 50 consumer instances each own one partition, processing orders in parallel.”
Consumer Group
A consumer group is a set of consumers that collectively consume a topic — each message in a partition is delivered to exactly one consumer in the group. Allows scaling consumption horizontally.
At-Least-Once vs. Exactly-Once Delivery
- At-least-once: the message may be delivered more than once (retry-safe consumers must be idempotent)
- Exactly-once: the message is delivered exactly once (complex to achieve, usually with Kafka transactions or at additional cost)
“We use at-least-once delivery and make all our consumers idempotent — processing the same event twice produces the same result.”
Idempotent Consumer
An idempotent consumer can safely process the same message multiple times without duplicating side effects. Critical for at-least-once delivery systems.
Schema Registry & Schema Evolution
Schema Registry
A schema registry is a centralised repository for event schemas — stores the definition of every event type and enforces schema compatibility when events are produced or consumed.
Popular implementations: Confluent Schema Registry, AWS Glue Schema Registry.
Avro / Protobuf Schemas
Avro and Protobuf are binary serialisation formats commonly used with schema registries. They are more compact and include schema evolution support compared to JSON.
Schema Evolution
Schema evolution is changing an event schema over time without breaking existing consumers. There are three compatibility modes:
- Backward compatible: new schema can read data written by old schema (add optional fields)
- Forward compatible: old schema can read data written by new schema (remove optional fields)
- Full compatible: both directions work
“Before publishing the new
OrderPlacedevent with an additionalcouponCodefield, we verified it was backward compatible — existing consumers that don’t know aboutcouponCodewill still work.”
Breaking Change (Schema)
A breaking change in an event schema is a change that makes existing consumers unable to deserialise new events — e.g., removing a required field or changing a field’s type. Breaking changes require version bumps and coordinated migration.
Key Phrases
| Situation | Phrase |
|---|---|
| Choosing choreography vs. orchestration | ”For simple flows, choreography keeps services decoupled. For complex multi-step sagas, orchestration gives better visibility and control.” |
| Explaining eventual consistency | ”After the command is processed, the read model will be updated within milliseconds — it’s eventually consistent, not immediately consistent.” |
| Describing event sourcing | ”We store every state change as an event — we can reconstruct the full history of any order at any point in time.” |
| Discussing schema evolution | ”The new field is optional and backward compatible — existing consumers don’t need to be updated.” |
| Explaining a DLQ | ”Failed events go to the dead letter queue — we monitor it daily and replay events once we’ve fixed the consumer bug.” |