Concept · Async work & messaging
Event sourcing and CQRS
Store the events, derive the state — and read from models built for reading.
Two patterns that are often used together, but are separate ideas.
Event sourcing
Instead of storing the current state of an entity and overwriting it, store the sequence of events that happened to it, and derive the state by replaying them.
account 7:
AccountOpened {owner: "ana"}
MoneyDeposited {amount: 100}
MoneyWithdrawn {amount: 30}
→ current balance = 70Benefits
- A complete, immutable audit history — why the state is what it is, not just what it is.
- Rebuild state, or build entirely new views, by replaying events.
- Natural fit with event-driven systems: the events are already there to publish.
Costs
- Querying current state needs projections (below); replaying long histories needs periodic snapshots.
- Events are forever, so their schemas must evolve compatibly (versioning, upcasting old events).
- Correcting mistakes means writing compensating events, not editing history.
- More complexity than most CRUD domains justify.
It shines where history is the point: ledgers and accounting, order lifecycles, audit-heavy domains. The payment lesson's double-entry ledger is a close relative: append-only entries from which balances are derived.
CQRS (command query responsibility segregation)
Use separate models for writes (commands) and reads (queries). The write model enforces business rules; one or more read models (projections) are shaped for specific queries — a denormalized table, a search index, a cache — and are updated from the write side's events.
- Reads can scale and be optimised independently.
- Read models lag the write model briefly (eventual consistency), so the UI must tolerate it — for example by showing the user's own change from the command's result.
Using them sensibly
You can use CQRS without event sourcing (a normal database plus read models fed by an outbox), which is common and useful. Event sourcing almost always implies CQRS. Apply either to the parts of a system that need it, not to everything. See normalization vs denormalization.