Skip to main content

CQRS (Command Query Responsibility Segregation)

CQRS separates the write model from the read model so each can be optimized and scaled independently. It pairs naturally with event sourcing and trades extra complexity and eventual consistency for flexibility.

Type
Architectural
When to Use
Read Write Asymmetry, Complex Read Models, Independent Scaling, Event Sourced Systems

CQRS splits an application into two models: one for changing state (commands) and one for reading state (queries). The traditional approach uses a single model for both, which forces one schema to serve writes and a wide variety of reads. CQRS lets each side be designed, optimized, and scaled on its own terms.

How It Works

Commands express intent to change something ("place order") and run through the write model, which enforces business rules and persists changes. Queries return data without side effects and run against one or more read models shaped for specific views. The read side is often a separate, denormalized store kept up to date asynchronously, typically by consuming events the write side emits. This makes reads fast and tailored, at the cost of eventual consistency between the two sides.

CQRS does not require event sourcing, but the two pair naturally: events from an event-sourced write model are an ideal way to build read models.

The command side typically uses a normalized transactional store that enforces invariants, while the query side may use several stores chosen per view: a document store for detail pages, a search engine for full-text queries, and a cache for hot lookups. The projection process that builds these read models can be replayed from scratch, which is valuable when a new view is added or a bug in a projection must be corrected.

When to Use It

Use CQRS when read and write workloads differ sharply, when the read side needs many specialized or denormalized views, when reads and writes must scale independently, or when you already use event sourcing. In microservices, a CQRS read model is a powerful way to answer queries that span services without runtime fan-out.

Avoid it for simple CRUD where one model serves both sides cleanly; CQRS adds complexity that such systems do not need.

It also suits collaborative domains where many users read shared data far more often than they change it, letting the read side absorb that traffic without contending with writes.

Trade-offs

Maintaining two models and the synchronization between them adds design and operational complexity. The read side is eventually consistent, so the UI may briefly show stale data, which the design must accommodate. Duplicated data needs more storage. These costs buy independent optimization, scalability, and clean separation of concerns. Teams usually adopt CQRS selectively, applying it only to the aggregates whose read and write demands genuinely diverge, rather than imposing the dual-model overhead across an entire system.

Related Patterns

CQRS frequently combines with Event Sourcing to build read models from an event log. It is an alternative to API Composition for cross-service queries over a Database per Service. Sagas often drive the commands in a CQRS write side.

Example

An e-commerce platform handles heavy product browsing and lighter ordering. The write side validates and stores orders and inventory in a normalized database. Each change publishes an event. A consumer updates a denormalized Elasticsearch read model powering search and product pages. Browsing scales independently and stays fast; orders remain consistent and rule-checked on the write side.