System Design
System Design/staff/freq 3/5

CQRS — When It Pays Off

Separate write model (commands) from read model (queries). Pays off when read/write shapes diverge dramatically or read scale dwarfs write. Otherwise it's just more code.

cqrsarchitectureddd

Deep dive

When yes

  • Reads need denormalized projections for performance.
  • Reads and writes have very different scaling needs.
  • You're already using event sourcing.

When no

  • CRUD over one DB. Don't add CQRS for "future-proofing".

Mechanics

Commands mutate the write model and emit events. Projectors consume events to build read models in optimized stores (search index, cache, materialized view). Reads serve only from projections — never query the write model directly.

Consistency

CQRS is eventually consistent by nature. UX must handle "I just placed an order, why isn't it in the list?" — read-your-writes via session-affinity or client-side optimistic update.

Real-world example

From production

Reporting dashboards killed the OLTP DB with complex joins. Introduced CQRS: writes to Postgres, projections to ClickHouse for analytics queries. OLTP latency stabilized; report queries went from 30s to 200ms. Tradeoff: ~2s lag between write and report, which the product accepted.

Interview questions

1 senior-level
Q1When would you introduce CQRS?

When read patterns diverge enough from write patterns that one schema can't serve both well — typically dashboards/analytics vs transactional writes, or massive read fan-out with small write volume. Don't introduce it for CRUD or 'cleanliness' — it doubles your operational surface.

Common mistakes

  • CQRS without a real read/write asymmetry — pure ceremony.

  • Forgetting read-your-writes UX.

Trade-offs

  • Two models = two places to evolve a feature.

  • Projections introduce lag, which the product must accept and design around.

Related