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.
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 productionReporting 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-levelQ1When 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.