CQRS is a pattern that separates read and write operations into distinct models, each optimized for its specific workload.
Core Idea
In a traditional CRUD application, the same data model handles both reads and writes. CQRS splits this into:
- Command Model (Write): Handles mutations — creating, updating, deleting data. Optimized for consistency and validation.
- Query Model (Read): Handles data retrieval. Optimized for fast lookups, denormalized views, and flexible querying.
Why Separate?
Reads and writes have fundamentally different scaling and optimization needs. A product catalog might receive 1000x more reads than writes. The read model can be denormalized, cached, and replicated aggressively without affecting write consistency.
Trade-offs
- Complexity: Two models to maintain, synchronize, and deploy instead of one
- Eventual consistency: The read model may lag behind writes, which is unacceptable for some use cases
- Overkill for simple domains: If your app is mostly CRUD with low traffic, CQRS adds overhead for little benefit
When It Makes Sense
- High read-to-write ratios (e.g., product catalogs, dashboards)
- Complex domains where read and write shapes diverge significantly
- Systems that need independent scaling of read vs. write workloads
- Often paired with Event-Driven Architecture and event sourcing