CQRS
Command Query Responsibility Segregation: using different models for reading and writing data. Reads and writes have different performance needs, so separate them.
What is CQRS?
In short
CQRS (Command Query Responsibility Segregation) is a design pattern that splits an application into two separate paths: one model that handles writes (commands) and a different model that handles reads (queries). Instead of one shared data model serving both, each side is shaped for its own job, so reads can be denormalized and fast while writes stay validated and consistent.
What CQRS actually means
In a normal application you have one model, say an Order entity, and the same code reads it and writes it. CQRS breaks that single model in two. A command is an instruction that changes state, like PlaceOrder or CancelOrder. A query is a request that returns data and changes nothing, like GetOrderHistory. The pattern says: handle these with separate models, and often separate code paths, separate services, and even separate databases.
The reason comes down to a mismatch most systems ignore. Writes need validation, business rules, and consistency. They are usually low volume. Reads are often 10x to 100x more frequent, need to be fast, and want data already shaped for the screen that shows it. Forcing both through one model means you either slow down reads with normalized tables and joins, or you weaken your write model to make reads convenient. CQRS lets each side win on its own terms.
CQRS does not require event sourcing, two databases, or any messaging. The simplest version is just two sets of code in the same service hitting the same database: command handlers that run business logic, and query handlers that run plain optimized SELECTs and skip the domain layer entirely. That alone is valid CQRS.
How it works under the hood
The write side accepts a command, validates it against business rules, and updates the authoritative data store. This is your source of truth. It stays normalized and consistent because correctness matters more than read speed here.
The read side serves queries from a read model that is optimized for display. In the full version, this read model lives in a separate store: a denormalized table, a document in MongoDB, a search index in Elasticsearch, or a cache in Redis. When the write side changes data, it publishes an event, and a projector listens for that event and updates the read model to match.
That last step introduces the most important property to understand: the read model is updated asynchronously, so it is eventually consistent. There is a small window, usually milliseconds, where a user who just wrote data could query the read side and not see their own change yet. Systems handle this by reading their own writes from the write side, or by showing an optimistic UI update until the projection catches up.
When CQRS is paired with event sourcing, the write side stores the full sequence of events rather than just the current state, and read models are built by replaying those events. The two patterns fit together well, but neither requires the other.
When to use it and the trade-offs
CQRS earns its complexity when read and write loads are very different, when the read shape differs a lot from the write shape, or when many different views need the same underlying data. A reporting dashboard, a product catalog with search and filtering, and a high-traffic feed are all good fits.
The cost is real. You now maintain two models, you accept eventual consistency on reads, and if you add separate stores and projections you take on the operational burden of keeping them in sync and handling projector failures. For a simple CRUD app where reads and writes look nearly identical and traffic is modest, CQRS is over-engineering that buys you nothing.
A common middle ground is to apply CQRS to one busy slice of a system rather than the whole thing. You might run plain CRUD for account settings while using full CQRS with a denormalized read store only for the order history view that gets hammered. The pattern is a tool you apply where the read and write mismatch actually hurts, not a rule you apply everywhere.
A concrete example
Picture an e-commerce checkout. When a customer places an order, the command handler validates stock, charges the card, and writes a normalized order row plus line items into PostgreSQL. That write path enforces every rule and is the source of truth.
Now the customer opens their order history page. That query does not touch the order tables or run six joins. It reads from a denormalized read model, one row per order with the product names, total, and status already flattened in, served from a read replica or a cache. The page loads in a few milliseconds even under heavy traffic.
Keeping the two in sync is the job of a projector. When the order is written, an OrderPlaced event fires, a background worker picks it up, and it upserts the flattened row into the read store. If the worker lags by 50 milliseconds, the history page might briefly miss the newest order, which is an acceptable trade for a read path that scales independently of the write path.
Where it is used in production
Microsoft eShopOnContainers
Microsoft's reference microservices app uses CQRS in its Ordering service: full domain model for commands, lightweight Dapper queries for reads.
Netflix
Splits write paths from read-optimized stores and serves many denormalized read views from data shaped for each UI surface.
Redis
Commonly used as the read-side store in CQRS, holding denormalized projections that serve queries in sub-millisecond time.
Elasticsearch
A frequent CQRS read model: the write side stays in a relational DB while a projector keeps a search-optimized index in sync.
Frequently asked questions
- Does CQRS require two separate databases?
- No. The simplest CQRS just uses two code paths against one database: command handlers with business logic and query handlers running plain optimized reads. Separate stores are an optional escalation for when read and write loads need to scale independently.
- Is CQRS the same as event sourcing?
- No, they are different patterns that often appear together. Event sourcing stores state as a sequence of events. CQRS separates read and write models. You can use either one without the other, though combining them is popular because events make it easy to build read projections.
- What is the main downside of CQRS?
- Complexity and eventual consistency. You maintain two models instead of one, and when you use separate read stores the read side lags the write side by a short window, so a user might not immediately see their own change on the read path.
- When should I not use CQRS?
- Skip it for simple CRUD apps where reads and writes have nearly the same shape and traffic is modest. The extra models and consistency handling add cost without payoff when there is no real read and write mismatch.
- How does the read model stay up to date?
- The write side publishes an event after each change, and a projector subscribes to that event and updates the read model. This happens asynchronously, which is why the read side is eventually consistent rather than instantly in sync.
Learn CQRS hands-on
This page explains the idea. The full lesson lets you step through the ring as servers join and leave, read the implementation, and check yourself with a quiz. It is one of 760+ lessons in the System Design Masterclass, from your first API call to distributed consensus. Eleven Foundation lessons are free, no signup. Lifetime access is ₹499 in India or $7.99 worldwide, one payment, no subscription.
Related lessons
Lessons that touch on CQRS as part of a larger topic.
Event Sourcing
Store events instead of state, rebuild any point in time from the log of what happened
advanced · distributed systems core
Data Aggregation
Combine data from multiple sources into a unified view, building the single source of truth
intermediate · data governance compliance
Command Bus
Route explicit instructions to the one handler responsible for executing them
intermediate · messaging event systems
Event-Driven Architecture
Build systems where everything reacts to events, the architecture powering Netflix, Uber, and LinkedIn at massive scale
intermediate · messaging event systems
Command Pattern
Encapsulate requests as objects, enabling undo, queuing, logging, and distributed task execution
intermediate · microservices architecture
See also
Related glossary terms you might want to look up next.
Event Sourcing
Storing every state change as an immutable event instead of just the current state. You can rebuild any past state by replaying events.
Saga Pattern
A way to manage distributed transactions across microservices using a sequence of local transactions with compensating actions for rollback.
Microservices
An architecture where an application is split into small, independent services that communicate over the network. Each service owns its own data and can be deployed separately.
CAP Theorem
In a distributed system, you can only guarantee two of three: Consistency, Availability, and Partition tolerance. You must choose your trade-off.
Consensus
The process of getting multiple nodes in a distributed system to agree on a single value. The foundation of distributed databases and coordination services.
Paxos
A family of protocols for solving consensus in unreliable networks. Famously difficult to understand but mathematically proven correct.