Reqflow
← All concepts
Data·3 min read

CQRS & Event Sourcing

Split the write model from the read model (CQRS) and store state as a log of events instead of current values (event sourcing).

Try it

Send a command (write), then a query (read). Two separate models.

Write modelcommandsv=0
projection
Read modelqueriesv=0

CQRS splits writes and reads into separate models. The write side enforces rules; a projection keeps a read side shaped for fast queries. Each scales on its own, at the cost of complexity and a brief lag before the read model catches up.

First time reading this? Start here

Plain English: CQRS means using one model/datastore optimized for writes and a separate one optimized for reads, instead of forcing both through one schema. Event sourcing means storing every change as an event ('deposited $50') and computing current state by replaying them, instead of just storing the latest balance. Powerful, but a lot of complexity.

What it is

Two related but separable patterns. CQRS (Command Query Responsibility Segregation) splits the system into a write side (commands that change state) and a read side (queries), each with its own model and often its own datastore. Event Sourcing stores state as an append-only log of immutable events; current state is derived by replaying those events, rather than by storing and overwriting the latest value.

The problem it solves

A single model optimized for both writes and reads compromises on both: normalized for write integrity but slow for complex reads, or denormalized for reads but awkward to update. CQRS lets each side be optimal independently. Event sourcing solves loss of history: a conventional table stores only the current value, throwing away how it got there, while event sourcing keeps the full audit trail, enables temporal queries ('what was the balance on March 1?'), and lets you rebuild read models by replaying events.

How it works

CQRS: commands go to the write model (often normalized, transactional); the write side emits events; one or more read models (denormalized, query-optimized, possibly in different stores) are updated from those events asynchronously. Reads hit the read models. Event sourcing: every state change is appended as an event to an event store. Current state = fold over the event stream. Snapshots periodically checkpoint state so you don't replay from the beginning every time. The two combine naturally, since event sourcing's event stream feeds CQRS read models, but each can be used without the other.

Why use it

  • Read and write models scale and optimize independently: denormalized reads, transactional writes
  • Event sourcing gives a complete, immutable audit trail and time-travel/temporal queries for free
  • You can build new read models retroactively by replaying the event log

What it costs you

  • Major complexity jump: two models, async projection, and replay logic to build and maintain
  • Read models are eventually consistent with writes, so the read side lags the write side
  • Event sourcing is hard to evolve: schema/versioning of historical events and replay performance become real problems

Where it shows up in our architectures

  • Payment Gateway

    The ledger is naturally event-sourced: append immutable debit/credit entries and derive balances; you never overwrite, giving a perfect audit trail

  • Stock Exchange (Matching Engine)

    An append-only event log of orders/trades is the source of truth; the in-memory order book is a read model rebuilt by replaying events on restart

  • Google Docs (Realtime Collab)

    The per-document operation log is event sourcing: document state is snapshot plus replayed deltas, the read model for editors

Gotchas

  • CQRS and event sourcing are separate patterns. You can do CQRS with two normal databases and no event log, or event-source without splitting reads. Don't adopt both reflexively; each adds complexity.
  • The read side is eventually consistent. A user who just wrote may not see their change immediately in the read model, so design the UI for it (optimistic update, read-your-writes routing).
  • Event versioning is the silent killer of event sourcing: events live forever, so changing their schema means handling every historical version on replay. Plan upcasting/versioning from day one.
  • Don't event-source everything. It shines for audit-critical, history-rich domains (ledgers, order books); for simple CRUD it's overkill that buys you nothing.
Interview angle

CQRS comes up when an interviewer asks how you'd design a system with very different read and write requirements, like a social feed with few writes but millions of reads per post. The key insight is that CQRS lets you optimize each path independently, with a separate denormalized read store. You don't have to pair it with event sourcing, so clarify that distinction. Candidates lose points by treating CQRS as an all-or-nothing pattern or by conflating it with event sourcing when the interviewer only asked about read-write separation.

Your notes

Private to you