How CQRS Works

Advanced
8 min read· Architecture & Design

CQRS — Command Query Responsibility Segregation — splits a system into two models: one for writes (commands that change state) and one for reads (queries that return data). In a traditional CRUD app, one model does both, which forces awkward compromises when reads and writes have very different needs. CQRS lets each side be optimised independently: a normalised write model for correctness, and denormalised read models tuned for fast, specific queries. It pairs naturally with event sourcing.

Think of a restaurant kitchen and menu

A kitchen (the write side) is organised for preparing food correctly — stations, raw ingredients, strict process. The menu and display counter (the read side) are organised for customers to browse quickly — photos, categories, prices. You would not force customers to read the raw kitchen inventory, nor cook from the glossy menu. CQRS keeps these two concerns separate: one structure optimised for doing the work, another optimised for showing the results.

Step by Step

1 / 5

Key Concepts

Command vs Query

A command changes state and returns no data (or just an ack); a query returns data and changes nothing. CQRS enforces this separation at the model level, not just the method level.

Read Model / Projection

A denormalised data structure built specifically to answer certain queries fast. Projections update it in response to changes on the write side, usually asynchronously.

CQRS + Event Sourcing

A common pairing: the write side stores events (event sourcing), and projections build read models by replaying those events. The two patterns reinforce each other but are independent.

Eventual Consistency (read side)

Because read models update asynchronously after writes, a read can briefly lag a just-committed write. The design must tolerate this small window.

Key Facts

  • CQRS adds real complexity — two models, projections, eventual consistency — so it is worth it only for complex or high-scale domains, not simple CRUD apps.
  • You can apply CQRS at any granularity, even just splitting read and write repositories, without going full event sourcing.
  • The biggest practical benefit is letting read models be shaped and scaled for exactly the queries a UI needs, independent of how data is written.

Real-World Applications

A complex reporting-heavy domain

An e-commerce backend writes orders through a validated, normalised model, while dashboards read from denormalised projections (revenue by day, orders per customer) that update from order events — fast reads without slowing writes.

Search alongside transactional data

The write model lives in a relational database; a projection feeds a search index (Elasticsearch) as a read model, so full-text queries are fast and never burden the transactional store.

Frequently Asked Questions

What is CQRS?

CQRS (Command Query Responsibility Segregation) is a pattern that separates the model used to change data (commands/writes) from the model used to read data (queries). Instead of one shared model doing both, each side is optimised independently — a consistency-focused write model and query-optimised read models — which helps complex or high-scale domains where reads and writes have very different needs.

Is CQRS the same as event sourcing?

No, they are separate patterns that are often used together. CQRS separates read and write models. Event sourcing stores state as a log of events rather than current values. They pair well — the event log feeds projections that build CQRS read models — but you can use either one without the other.

When should I use CQRS?

Use it when a domain is complex or high-scale and the read and write sides have genuinely different requirements — for example, heavy reporting on top of transactional writes, or very different read and write throughput. For simple CRUD applications, CQRS adds complexity (two models, projections, eventual consistency) without enough benefit.

What is a projection in CQRS?

A projection is the process (and resulting data structure) that builds and maintains a read model from changes on the write side. When the write model changes — often by publishing events — projections update the denormalised read models so they reflect the latest state, typically asynchronously, which is why read models are eventually consistent.

Related Topics