Skip to main content
cd ../lexicon
sys/docs/lexicon/cqrs-command-query-responsibility-segregation.md
Lexicon

CQRS (Command Query Responsibility Segregation)

Difficulty: Advanced
3 min read

In plain English

Plain definition

A pattern where you use one model/pipeline to accept writes and a separate, denormalized model/pipeline to serve reads, instead of one schema doing both jobs.

CQRS partitions a service’s data-access surface into two distinct code paths: a command side that validates business invariants and mutates authoritative state, and a query side that serves reads from one or more denormalized projections. The command side typically writes to a normalized store or an event log (frequently paired with Event Sourcing, though the two are not required to co-occur). The query side subscribes to the resulting change stream — via CDC, an outbox relay, or domain events — and materializes purpose-built read models: a search index, a graph store, a flattened SQL table, or an in-memory cache keyed exactly to a UI’s access pattern.

The critical architectural consequence is that the read models are eventually consistent with the write model. There is a propagation delay between a command committing and every projection reflecting it, and this delay is variable under load, replication lag, or consumer backpressure. Systems must explicitly decide how to handle the read-after-write gap: sticky routing to the primary for the originating session, client-side version tokens compared against projection watermarks, or simply accepting stale reads with a documented SLA. Ignoring this gap is the single most common production incident vector — engineers assume the pattern behaves like a synchronous ORM and build UX or downstream logic that silently breaks under lag.

  • Command side design: commands are intent-bearing, validated against invariants, and typically produce one canonical write plus zero or more domain events; concurrency control (OCC or a version column) prevents lost updates.
  • Query side fan-out: a single command can drive N independent projections at different consistency lags — a search index might update in seconds, a data-warehouse rollup in hours. Each projection needs independent replay/rebuild tooling since schema changes require reprocessing the event history.
  • Failure isolation: a broken projector should never block the command path; the outbox/queue between them must be durable and independently scalable, or the pattern degenerates into a distributed monolith with two synchronized failure domains instead of one.
  • Idempotency: projectors consume from an at-least-once delivery substrate, so projection updates must be idempotent (upserts keyed by event ID/offset, not blind appends).

CQRS is frequently conflated with simple read-replica offloading. A read replica keeps the identical schema and identical query capability as the primary, just on separate hardware — it solves throughput, not shape mismatch. CQRS restructures the data model itself: the read side can be a different storage technology entirely (e.g., Elasticsearch for the query model backed by Postgres for the command model), which is what unlocks query patterns (full-text, graph traversal, multi-dimensional aggregation) that the write-optimized schema was never designed to serve.

The pattern’s cost is organizational and operational complexity: two schemas to version, a rebuild/replay pipeline for every projection, monitoring for consumer lag as a first-class SLO, and developer discipline to never let query-side code leak back into command-side invariant enforcement. It is justified only when read and write access patterns have genuinely diverged enough that a single model can no longer serve both without compromising one of them — applying it prophylactically on a CRUD service with symmetric read/write shapes adds two moving parts to maintain zero additional capability.

CQRS (Command Query Responsibility… | KBY Lexicon