pattern

CQRS in Practice

also called Command Query Responsibility Segregation

Separating the write model from read models, what it genuinely buys, and why it is one of the most over-applied patterns in enterprise architecture.

cqrsread-modelsconsistencycomplexity

Definition

Separating the model used to change state from the model or models used to read it. In its lighter form that is two sets of objects against one database; in its full form, separate stores kept in sync asynchronously.

Why it matters

Because read and write workloads frequently want incompatible shapes. Writes want normalisation and invariants enforced in one place. Reads want denormalised, query-shaped data with no joins.

Forcing both onto one model means compromising both — and the compromise usually lands on reads, which is where the volume is. A system where the write model is correct and every read requires six joins against tables designed for consistency is the situation CQRS addresses.

The second driver is independent scaling: reads typically outnumber writes by orders of magnitude, and separating them lets each scale on its own profile.

Implementation patterns

Same database, separate models. Commands go through the domain model; queries use lightweight projections or views. No consistency lag. This covers a large share of real cases and is where most teams should stop.

Separate read store, synchronously updated. A denormalised table maintained in the same transaction. Still consistent, some write cost.

Separate read store, asynchronously updated from a change stream or event log. Full separation, full independence — and eventual consistency between write and read.

Multiple read models from one change stream: a search index, an analytical table, a cache, a per-client projection. This is where the pattern genuinely earns its complexity.

Failure scenarios

Silent divergence. The read model drifts from the write model through a missed event, an out-of-order apply or a projection bug. It looks plausible, nobody notices for weeks, and the reconciliation job that would have caught it was never built.

No rebuild path. A projection defect requires rebuilding from history — and if that takes eleven hours during which the feature is unavailable, the design is incomplete.

Read-your-writes violated. A user submits a change and the next page renders from a read model that has not caught up, so their change appears to have been lost. This is the most common user-visible failure and it needs an explicit answer.

Applied everywhere. CQRS on simple CRUD produces two models to maintain, an eventual consistency problem and a synchronisation mechanism, for a system where a table would have done.

Industry example

The social timeline is CQRS at scale. The write model is a post; the read model is a per-user precomputed timeline, maintained asynchronously by fan-out. Twitter's publicly-described hybrid — fan-out on write for ordinary accounts, read-time merge for very high-follower accounts — is a read model with an escape hatch for the pathological tail.

Trade-offs

Gains: read and write models each optimised, independent scaling, multiple purpose-built read models, and read models that can be rebuilt.

Costs: eventual consistency and its user-visible consequences, a synchronisation mechanism to operate, a rebuild path to build and test, reconciliation to detect divergence, and substantially more moving parts to debug.

Interview question

A team proposes CQRS with separate read and write databases for a customer preferences service. What questions do you ask?

Good candidates probe for the driver: what read load justifies separation, how many distinct read models are needed, and what the consistency requirement is. They should note that preferences are typically last-value-wins state read by their owner immediately after writing — the worst case for eventual consistency — and that the lighter same-database form, or no CQRS at all, is likely correct.