MicroservicePatterns.com
Data management · Advanced

CQRS

The CQRS (Command Query Responsibility Segregation) pattern separates the model that handles writes and enforces business rules from read models that are built for specific queries.

Last updated

What is the CQRS pattern?

Command Query Responsibility Segregation splits the write side, which enforces business rules, from the read side, which serves queries. The read side holds denormalised views shaped for specific screens or searches, and is updated from events published by the write side.

What problem does the CQRS pattern solve?

When each service owns its data, a screen that needs data from three services can no longer use a join. Read and write workloads also differ in shape and volume, and one model rarely serves both well. A purpose-built read model answers a query with one fast lookup.

How do you implement the CQRS pattern?

  1. Find the queries that are slow, span several services or need a very different shape from the write model.
  2. Build a read model for each, such as a table, search index or cache, shaped exactly for that query.
  3. Update it from the write side's events, ideally published through an outbox.
  4. Send commands to the write model and queries to the read model.
  5. Plan for staleness: show when data was last updated, and make sure the person who just wrote can see their own change.

When should you use it?

  • Queries join data owned by several services.
  • Reads vastly outnumber writes, or need different scaling or storage.

When should you avoid it?

  • Simple CRUD where one model works fine.
  • The business cannot accept any delay between a write and the view of it.

What do you gain?

  • Fast queries shaped for the screen
  • Reads and writes scale independently
  • Solves cross-service queries without runtime joins

What does it cost?

  • Eventual consistency between sides
  • More components and duplicated data
  • Needs a way to rebuild read models

What are common mistakes with the CQRS pattern?

  • Applying CQRS to every service instead of the few that need it.
  • Putting business rules in the read model.
  • No way to rebuild a read model after a bug or schema change.

CQRS in practice

Illustrative scenario · fictional company

Corvid Careers

Profile edits needed strict validation in the relational store, while member search needed full-text and faceted queries. Search load on the primary database slowed down edits.

Writes stay in the relational store, and changes stream to a search index that serves queries. Search results can lag an edit by a few seconds, which the UI accounts for.

Example decision record
Context
Analytics dashboard queries compete with core writes on the primary database.
Decision
Project write-side events into a separate search store that serves dashboard queries.
Consequences
  • The primary database no longer carries heavy secondary indexes for reporting.
  • The UI must tolerate a short delay between an update and the query result.