When to reach for it
- Your read and write workloads have wildly different shapes and your indexes are at war with each other
- The natural shape of the write model — rich aggregates, invariants — produces terrible read queries with seven joins
- You need multiple read shapes (customer view, admin view, search index) and projecting once per view is cheaper than denormalising on the fly
- You're already on an event-driven backbone, so projections come almost for free
- Audit and replayability matter — you want to rebuild a read model from history when you discover a bug
What it actually costs
Eventual consistency becomes a UX problem — a user creates an order, navigates to the list, doesn't see it. You need projection workers, lag monitoring, replay tooling and an answer for 'why is the data different in these two places'. The team must internalise that there are two models for the same domain and contributing to both is the norm. CQRS without events still works, but most teams pair it with event sourcing, doubling the conceptual load.
The failure mode nobody mentions
Projection drift. A bug in the projection handler silently miscounts something for a week, the read and write models disagree, and you find out because finance reconciliation fails — not because anything blew up. By then the bad data is in three downstream systems that fed off the projection, and 'just replay from events' takes a weekend because the projection logic has changed five times since.
When not to use it
Your read and write models look the same and a single relational schema with sensible indexes serves both — CQRS gives you two of everything to solve a problem you don't have.