CQRS vs. traditional CRUD: when the split actually pays off
January 14, 2025 · sydep team · 2 min read
Most services start as a single model doing double duty: the same tables and the same objects serve both writes and reads. That's the right default. CQRS (Command Query Responsibility Segregation) only earns its complexity once reads and writes have genuinely different shapes, scaling needs, or consistency requirements.
The symptoms worth watching for
- Your read queries are joining across half a dozen tables to build a single view, and that view is requested far more often than the underlying data changes.
- Writes need strict validation and transactional guarantees, but reads would be perfectly happy with a slightly stale, denormalized copy.
- You want to scale read replicas independently from your write path, or swap in a different storage engine (a search index, a cache, a columnar store) purely for queries.
If none of those are true yet, a single model with good indexes will take you further than a segregated architecture. Splitting too early mostly adds synchronization bugs.
What the split actually looks like
At its simplest, CQRS means: commands go through a write model that enforces invariants, and an event or change-data-capture stream projects that write model into one or more read models shaped for specific queries. The read models can be eventually consistent — and usually should be, since that's what buys you the scaling and shape flexibility in the first place.
See the CQRS pattern reference for a diagram of the component layout, or read about the event sourcing pattern if you're also considering storing state as an append-only log of events rather than current-state rows.
A pragmatic rollout path
- Keep a single write model as the source of truth.
- Add one denormalized read model for your worst-offending query — not all of them at once.
- Measure whether the eventual-consistency window (usually milliseconds to low seconds) actually matters to your users. Often it doesn't.
- Only generalize the pattern to more of the system once the first read model has proven itself in production.
Want to see how this fits into a larger system? Try it out in the canvas and wire a CQRS block into an existing design.