Skip to main content

CQRS (Command Query Responsibility Segregation)

CQRS splits the write model from the read model so each can be optimized and scaled on its own. It is valuable when read and write workloads diverge, but its added complexity means it should be applied selectively, not by default.

Organization
Martin Fowler
Published
Jul 14, 2011

Best Practice: CQRS (Command Query Responsibility Segregation)

CQRS separates the responsibility for changing data from the responsibility for reading it. Instead of one model handling both, you have a command side optimized for writes and validation, and a query side optimized for reads and presentation. The two sides can use different data stores, different schemas, and scale independently. Greg Young popularized the term, building on Bertrand Meyer's command-query separation principle. CQRS matters when read and write workloads are very different in shape or volume, or when a single shared model becomes too complex to serve both jobs well. It is a powerful pattern, but it adds complexity, so it should be applied selectively rather than everywhere.

Step-by-Step Implementation Guidance

  1. Identify a bounded context where read and write needs genuinely diverge.
  2. Define commands as explicit intent-carrying messages that mutate state.
  3. Define queries as read-only operations that never change state.
  4. Build separate write and read models; the read model can be denormalized for fast queries.
  5. Choose a synchronization mechanism, often events, to update the read model after writes.
  6. Decide on consistency: accept eventual consistency between sides unless strong consistency is essential.
  7. Add monitoring for synchronization lag so stale reads are visible.

Common Mistakes Teams Make When Ignoring This Practice

  • Forcing one model to serve wildly different read and write loads, hurting both.
  • Applying CQRS everywhere, adding needless complexity to simple CRUD apps.
  • Ignoring eventual consistency and surprising users with stale data.
  • Coupling the read and write models so tightly that the separation provides no benefit.
  • Skipping monitoring of replication lag between the two sides.

Tools and Techniques That Support This Practice

  • Message brokers such as Apache Kafka or RabbitMQ for propagating changes.
  • Event Sourcing as a complementary pattern for the write side.
  • Read-optimized stores like Elasticsearch or materialized views.
  • Frameworks such as Axon Framework or MediatR for command and query dispatch.

How This Practice Applies to Different Migration Types

  • Cloud Migration: Split read replicas across regions to serve global queries while writes stay centralized.
  • Database Migration: Introduce a new read model alongside the old store before retiring it.
  • SaaS Migration: Build reporting read models without burdening the transactional SaaS write path.
  • Codebase Migration: Separate write and read paths as a step toward decomposing a monolith.

Checklist

  • Confirm the bounded context truly has divergent read and write needs.
  • Model commands as explicit intent messages.
  • Keep queries strictly read-only.
  • Build a denormalized read model for query performance.
  • Choose and document the consistency model.
  • Implement reliable synchronization between sides.
  • Monitor and alert on read-model replication lag.