How it works
Separate operations by responsibility. Commands express intent, such as ReserveRoom or PublishPost, and validate business rules before changing state. Queries retrieve data without changing business state, such as searching available hotels or loading a home feed.
Give each side a model suited to its job. A hotel booking write model might store inventory by hotel, room type, and date, with transactions preventing overselling. Its read model might contain searchable hotel documents with location, amenities, and summarized availability.
Start with logical separation, not necessarily separate infrastructure. Command handlers and query handlers can use the same database while exposing different models. Separate databases, services, or asynchronous updates are options, not requirements of CQRS.
When using separate stores, propagate committed changes reliably. A transactional outbox can record a change alongside the business transaction, or change data capture can read committed database changes. Consumers then update query-specific projections; retries require idempotent processing, and older updates must not overwrite newer state.
Define what readers see while projections catch up. Search may temporarily show a room that has just sold out, but the reservation command must check authoritative inventory again. For read-your-writes behavior, return committed state from the command, temporarily read the write store, or wait until the projection reaches a returned version.
A worked example
Hotel search versus reservation correctness
Suppose a hotel service handles 10,000 searches and 100 reservation attempts per second. The command side stores inventory per room type and date in a transactional database. A three-night reservation atomically checks and reduces inventory for all three dates. The same transaction writes an outbox record. Consumers update a search projection designed for location and amenity filters, with a target lag below two seconds. A search result can therefore show a room that is no longer available; booking always rechecks the transactional store. The reservation response returns the confirmed booking directly rather than waiting for search to catch up. If consumers fail, booking remains correct, but search freshness degrades and must be monitored.
Trade-offs to say out loud
- Better query shapes versus duplicated data
- Denormalized read models avoid expensive query-time joins, but consume storage and require maintaining multiple representations.
- Independent scaling versus more infrastructure
- Separate stores let search and transactional writes scale differently, but add consumers, deployment dependencies, and failure modes.
- Fast asynchronous reads versus stale results
- Asynchronously updated projections reduce coupling to writes, but require explicit freshness guarantees and read-your-writes behavior.
- Clear business rules versus extra application structure
- Command models make invariants explicit, but separate handlers and models can be unnecessary overhead for straightforward CRUD.
- Rebuildable projections versus recovery work
- Read models can be rebuilt only if retained source data supports it, and rebuilding requires capacity planning and a safe catch-up process.
When to reach for it
- Search, feeds, or dashboards need data organized very differently from the transactional source of truth.
- Writes must enforce strict invariants, while discovery or reporting reads can tolerate a defined amount of staleness.
- Complex joins or aggregations dominate read latency, making precomputed query models useful.
- Read and write workloads need different storage engines, indexes, or scaling policies.
How to bring it up in the interview
- Start with the mismatch: explain why one model is awkward for both transactional changes and the required queries, rather than introducing CQRS just because reads outnumber writes.
- Draw the command path, authoritative store, propagation mechanism, and read projection; state exactly when a command is acknowledged.
- Assign a consistency requirement to each read: discovery may be stale, but inventory allocation, permissions, or spending decisions may require authoritative checks.
- Expect probes about lost updates, duplicate events, and reordering; explain the outbox or CDC boundary, idempotent projection updates, and per-entity versions.
- Explain how you measure projection lag and recover from an outage, including whether you can rebuild from a snapshot plus captured changes or retained events.
Common mistakes
- Treating CQRS as synonymous with event sourcing; CQRS does not require storing business state as a sequence of events.
- Assuming separate databases, microservices, or eventual consistency are mandatory.
- Calling a read replica CQRS without identifying distinct command and query models; replication alone does not create that separation.
- Updating the write store and publishing a message as two unrelated writes, leaving a crash window that can permanently miss a projection update.
- Trusting a stale projection to enforce scarce inventory, financial limits, or access revocation without an appropriate authoritative check.
Where it comes up
Interview questions where cqrs is part of a strong answer, and why.
- Design Facebook post searchThe transactional post model and asynchronous search index need separate correctness rules for indexing, deletion, and permission-sensitive retrieval.
- Design a news feed like FacebookAuthoritative posts and follow relationships drive denormalized home-feed projections optimized for fast reads.
- Design a hotel booking systemDate-aware search can use a stale read projection while reservation commands enforce inventory constraints transactionally.
- Design a restaurant review app like YelpReview writes must reliably update query-oriented restaurant ratings and search projections across edits, deletions, and retries.
- Design Facebook likes at scaleAuthoritative user like state is separated from asynchronously maintained counts designed for high-volume reads and live delivery.
- Design Facebook MarketplaceListing commands maintain authoritative state while nearby discovery uses a separately updated search model that may lag.
Questions people ask
What is the CQRS pattern?
CQRS, or command query responsibility segregation, separates the model used to change business state from the model used to retrieve it. The separation can exist within one application and database, or extend to independently maintained read stores.
What is the difference between CQRS and event sourcing?
CQRS separates command and query responsibilities. Event sourcing stores authoritative state as a sequence of events rather than only the latest record. They can be combined, but CQRS can use ordinary database rows, and event sourcing does not require a separate read store.
When should you avoid CQRS?
Avoid it when a straightforward CRUD model meets your query, correctness, and scaling needs. Separate asynchronous projections are especially hard to justify when most reads need immediately current state. Start with a shared database and explicit query models if logical separation alone solves the problem.