sydepsystem design atlas

CQRS

Separate models and stores for writes and reads.

AdvancedDataPlatform
ClientClientCommand ServiceComputeWrite StoreStorageChange EventsMessagingProjectorAnalytics & DataRead StoreStorageQuery ServiceCompute

Commands go through a write model optimised for consistency; queries are served from a read model optimised for the shapes clients actually need, kept in sync asynchronously via events.

When to use it

  • Read and write workloads have very different volume or shape requirements
  • Query patterns need denormalised views that would be awkward to maintain in the write schema

Trade-offs

  • Read models are eventually consistent with the write side
  • Two schemas (and a sync path) to build, test and operate instead of one

Components used

Single-Page AppManaged App ServiceRelational DatabaseEvent StreamStream ProcessingDocument Database

How it works

  • Commands go through a write model optimised for validation and consistency; queries hit a separate read model shaped for exactly the views the UI needs.
  • The read side is kept up to date asynchronously from the write side, usually by consuming change events.
  • Because the two sides are separate, they can use different databases, scale independently and be denormalised differently.

Used in the wild

  • Read-heavy systems where the query shape is nothing like the normalised write schema.
  • Reporting and dashboard views that would otherwise require expensive joins against transactional tables.
  • Domains with complex write-side invariants but simple, high-volume reads.

Good to know

  • Greg Young named it, and has since spent years telling people they probably do not need it. CQRS is frequently applied to systems whose read and write loads are nearly identical, where it only adds moving parts.
  • It does not require event sourcing, and event sourcing does not require it — the two are routinely conflated because they were popularised together.