CQRS splits the write path (commands that change state) from the read path (queries that return data). Event Sourcing stores the sequence of events that produced state, instead of the state itself. They're often paired and often confused with each other; they're independent ideas that compose well — and bring the highest complexity ceiling on this list. Reach for them when audit, replay, or read-model variety is a real product requirement, not before.
← Back to ArchitectureReads and writes have different needs. Writes care about invariants, transactions, validation. Reads care about query shape, joins, latency. Forcing one model to serve both leads to overloaded entities and slow joins — or denormalization that drifts out of sync with the rules.
CQRS lets each side optimize independently. Write side: a normalized OLTP DB tuned for consistency. Read side: a denormalized projection (Postgres views, Elasticsearch, Redis, a graph index) shaped for the queries that actually run.
Sync (same transaction): writes update the read model atomically. No staleness, no extra infra, but the read model has to live in the same DB.
Async: writes emit events; a projector updates the read model after the fact. Read can lag by milliseconds to seconds. The classic CQRS shape.
Async projection means "save then read" can return stale data. UIs need to plan for this — optimistic updates, "your change is processing" states, or a read-from-write fallback for the user's own recent writes.
Don't UPDATE rows. Append events. OrderPlaced, ItemAdded, DiscountApplied, OrderShipped — every state change is recorded as a fact. To get the current state of an order, replay its events from the start.
Purpose-built: EventStoreDB, Axon Server, Marten (Postgres-based, .NET). Many teams roll their own on top of Postgres or Kafka — append-only table, monotonic version per aggregate, careful indexing.
A typical CQRS+ES request flow:
PlaceOrder) to the write side.Workflows that span aggregates use process managers / sagas reacting to events.
| Signal | Verdict |
|---|---|
| Audit trail is a hard requirement (finance, healthcare, regulated industry) | Event Sourcing is a strong fit. |
| Reads vastly outnumber writes, with multiple query shapes | CQRS pays off. |
| Domain is naturally event-shaped (workflow, ledger, claims processing) | Both are natural fits. |
| You'll need to build new read models retroactively | Event Sourcing wins. |
| CRUD app: users edit rows | Don't. Use a layered or modular monolith. |
| Team has never operated an event store | Defer. The learning cost is real. |
| You want CQRS only for query separation | Use read replicas / materialized views first; full CQRS adds infra. |
"Most applications most of the time should not use Event Sourcing." — Greg Young, who coined CQRS, on the appropriate use of his own pattern.