CQRS definition
CQRS means Commands change state through a write model, while Queries read from models shaped for specific questions. The write side focuses on decisions and invariants. The read side focuses on projection shapes for UI, search, analytics, or operations.
Search interest in “CQRS” usually includes three questions: what CQRS means, how it differs from Event Sourcing, and when the pattern is useful instead of ordinary CRUD.
- Commands express business intent on the write side
- Queries use dedicated read models or Projections
- Invariants stay in Aggregates, not in Projection handlers
- Eventual consistency is an explicit tradeoff, not an accident
When CQRS pays off
CQRS is useful when the write side contains meaningful decisions while reads require different shapes: flat lists, full-text search, analytics, denormalized cards, or data from several Aggregates. Separate models protect the domain without forcing the UI to reconstruct a convenient view from a behavioral object graph.
For straightforward CRUD with similar read and write shapes, CQRS may add unnecessary types, handlers, and failure modes. Apply it to a specific source of complexity, not as a badge of DDD.
- Complex invariants on the write side
- Several substantially different read views
- High or independently scalable read traffic
- Queries combining data across boundaries
- Different storage and scaling requirements
The command path
A Command expresses intent and carries the information needed for a decision. Its handler locates the target, loads the Aggregate, invokes domain behavior, and persists the result. The Aggregate accepts or rejects the intent based on current state and invariants.
A successful decision emits Domain Events. The handler should not replace the Aggregate by reproducing its rules in the application layer. A synchronous acknowledgement can confirm acceptance without promising that every read model is already updated.
Projections and read models
A Projection builds a view for a specific question: OrderSummary, TicketBoard, CustomerBalance. It handles Events and updates a query-friendly structure. The same fact may feed several Projections for UI, search, reporting, or integration.
Store only what the consumer needs and design the read contract from that consumer. A read model should not become a second Aggregate: it displays facts but does not make business decisions.
Consistency and user expectations
Asynchronous read-model updates introduce eventual consistency: a Command has succeeded while a Query still returns an older view. The UI and API must account for this. Return an operation identifier, show an optimistically confirmed change, wait for a Projection version, or display processing state explicitly.
Do not promise read-your-writes unless the architecture provides it. Critical flows may use a synchronous Projection or confirmation from the write side, but that tradeoff should be explicit.
Idempotency and event ordering
Projection handlers must tolerate duplicate delivery. Track an event identifier, processed position, or version so the same change is not applied twice. When order matters, define its scope: global ordering is expensive and usually unnecessary, while per-Aggregate ordering can be guarded with versions.
A late Event must not silently overwrite newer data. Conflict handling is part of the design of each Projection.
Rebuilding and versioning projections
Projections are derived data, so they should be rebuildable from a reliable event or change source. When the schema changes, build a new version in parallel, validate it, and switch Queries after it catches up instead of mutating a live table in place.
Without complete event history, define a backfill source in advance: write-model snapshots, integration-event logs, or a migration query. CQRS does not make rebuilding automatic without such a source.
CQRS and Event Sourcing are separate choices
CQRS separates Command and Query responsibilities. Event Sourcing stores state as an event sequence. They are often combined but can be adopted independently: CQRS with a conventional transactional write model, or Event Sourcing with a simple query interface.
Choose Event Sourcing only when decision history, temporal queries, or state reconstruction justify event versioning and migration complexity.
Implementation mistakes
Creating CommandDTO and QueryDTO over one anemic model is not meaningful separation. Another extreme is splitting services and databases immediately when two modules in one process would solve the problem. Avoid one universal read model that gradually serves every Query.
Do not place business rules in Projection handlers. If a Projection decides whether a change is allowed, it has become a hidden write model.
CQRS design checklist
Before adoption, state which concrete complexity the separation removes and how the system behaves under delayed or duplicate Events.
- Are Commands named as business intentions?
- Do invariants remain inside Aggregates?
- Does each Projection answer a specific question?
- Is acceptable read-model lag defined?
- Are Projection handlers idempotent?
- Is ordering and late-event handling explicit?
- Can a Projection be rebuilt or migrated?
- Does the UI represent asynchronous processing honestly?
CQRS FAQ
What is CQRS?
CQRS means Command Query Responsibility Segregation. It separates the model that accepts Commands and protects business invariants from models optimized for reading. CQRS is a responsibility split, not a mandatory stack of brokers, microservices, or Event Sourcing.
When should you use CQRS?
Use CQRS when writes contain meaningful decisions while reads need different shapes: lists, search, analytics, denormalized cards, or data from several Aggregates. For simple CRUD with similar read and write shapes, CQRS often adds unnecessary complexity.
Is CQRS the same as Event Sourcing?
No. CQRS separates Command and Query responsibilities. Event Sourcing stores state as a sequence of events. They are often combined, but you can use CQRS with a conventional transactional write model, or Event Sourcing with a simple query interface.
What is a CQRS projection or read model?
A Projection builds a read model for a specific question, such as OrderSummary or TicketBoard. It handles Domain Events and updates a query-friendly structure. A read model displays facts for UI or reporting; it should not become a second place for business decisions.
Does CQRS require eventual consistency?
Often yes for asynchronous projections, but not always. If a Projection updates asynchronously, a Command can succeed while a Query still returns older data. The UI and API must handle that lag. Critical flows can use synchronous confirmation when the tradeoff is explicit.
DDDesigner
Example: OrderSummary and fulfillment board
The Order Aggregate accepts PlaceOrder, ConfirmOrder, and CancelOrder while protecting lifecycle rules. OrderPlaced, OrderConfirmed, OrderPaid, and OrderCancelled update OrderSummary for the customer-order list. A separate FulfillmentBoard combines InventoryReserved, PaymentCaptured, and DeliveryScheduled for operations. Duplicate Events are ignored by identifier, Aggregate versions protect ordering, and the UI shows processing state until the required Projection version has been applied.
Start free