Skip to content
Devgo

CQRS

Separating the read model from the write model so each can be optimized independently. Writes go through commands to a normalized store; reads come from optimized projections. Often paired with event sourcing.

When to use
  • Read-heavy domains with many query shapes.
  • Event-sourced systems where projections are natural.
When not to
  • Simple CRUD where one model suffices.
  • When eventual consistency between reads/writes is unacceptable.

Definition

Command Query Responsibility Segregation splits mutation (commands) from queries. The write side enforces invariants; the read side serves denormalized, query-optimized views, updated asynchronously from the write side.

Why it exists

One model rarely serves both strict writes and fast varied reads. CQRS lets you scale and shape reads (many projections, caches) without burdening the write path with query optimization.

How it works

Commands validate and persist to the write store, then emit events/updates that flow to read models. Reads query projections directly, often eventually consistent. The two sides can use different stores (e.g. Postgres write, Elasticsearch read).

Scaling limits

between write and read models. More infrastructure (projections, sync). Complexity rises; debugging requires tracing across models. Only worth it for complex or high-scale domains.

Cost shape

More stores and sync pipelines = more infra and ops. Blow-ups: projection lag, duplicate sync infrastructure.

Alternatives

  • Single model — Simpler, but reads and writes fight for the same shape.
  • Materialized view — Read optimization without full CQRS, DB-managed.

Failure modes

  • Projection lag causing stale reads.
  • Write/read model divergence.
  • Operational complexity obscuring bugs.

, ,