CQRS & Event Sourcing
You'll learn to
- -Separate a write model from a read model (CQRS) and explain what problem that split solves
- -Model state as a sequence of events (event sourcing) rather than a single mutable current-state row
These two patterns are frequently mentioned together, and they compose well, but they solve different problems - CQRS is about separating how you write from how you read; event sourcing is about how you actually store state in the first place. This chapter builds on the CQRS and event-sourcing chapters from LLD Fundamentals' schema-design track, applied here to API and service design specifically.
CQRS: Separate Models for Writes and Reads
Command Query Responsibility Segregation splits an API's write path (commands - mutations that change state) from its read path (queries - fetching data), letting each be optimized independently. A write model might be normalized and transaction-safe; a read model might be a heavily denormalized, pre-joined view optimized for exactly the queries clients actually make - the same write-optimized-versus-read-optimized trade-off from LLD Fundamentals' schema chapter, but expressed here as two separate API surfaces (or even two separate services) instead of two database schemas.
Event Sourcing: State as a Sequence of Events
[
{"event": "AccountOpened", "account_id": 42, "initial_balance": 0},
{"event": "FundsDeposited", "account_id": 42, "amount": 100},
{"event": "FundsWithdrawn", "account_id": 42, "amount": 30}
]
// current balance = replay every event in order: 0 + 100 - 30 = 70
// NOT stored as a single mutable "balance: 70" row anywhereInstead of storing only the current state and overwriting it on every change, event sourcing stores every state-changing event, and current state is derived by replaying them - this preserves complete history for free (exactly the append-only ledger technique from LLD Fundamentals' financial-modeling chapter) and lets the same event log support multiple different read models built by replaying events differently, which is exactly where event sourcing and CQRS compose naturally: the write side appends events, and one or more independently-optimized read models are built (and rebuilt, if needed) by replaying that same event log.
The API-Design-Specific Question: Eventual Consistency
Because the read model is built from events asynchronously, a client that just issued a command (write) and immediately queries the read model might not see its own change reflected yet - a real API design decision, not just an implementation detail. Options include: accept the eventual-consistency window and design the client experience around it (optimistic UI updates, for instance), or offer a way for a client to read its own writes immediately (routing that specific read back through the write model, or returning enough data in the command's own response that a follow-up read isn't needed right away).
CQRS and event sourcing are real architectural complexity - two models to keep conceptually separate, an event log to design and maintain, and an eventual-consistency window every client-facing flow has to account for. They earn their place for genuinely read-heavy systems with very different read and write access patterns, or where full historical auditability is a hard requirement - not as a default architecture for a typical CRUD-shaped service.
Interview Signal is part of Pro
See a real weak answer next to a real strong one for this exact topic.
Quiz is part of Pro
Test what you just read with a short quiz, and bank the XP.
Design CQRS Command Center in the API Design Lab's gRPC & Event-Driven act.