CQRS Interview Guide: When to Split Commands and Queries in a System Design
CQRS is the pattern candidates propose to sound sophisticated and then can't justify. Here is when to actually split reads and writes, what it buys you, and the price you pay for it.
CQRS Interview Guide: When to Split Commands and Queries in a System Design
CQRS — Command Query Responsibility Segregation — is the pattern candidates reach for when they want to sound sophisticated and usually shouldn't. It's also the pattern that, applied correctly, is the cleanest way to scale a read-heavy domain with complex write-side invariants. The gap between those two outcomes is what interviewers probe for.
This guide is the CQRS conversation as it plays out at staff and principal system design loops. It assumes you've heard the term. What the interviewer wants is evidence that you know when CQRS is genuinely the right call, what it costs, and how to avoid the foot-guns that have made it controversial in the community.
What CQRS actually is (and what it isn't)
Greg Young coined CQRS in 2010, building on Bertrand Meyer's older Command-Query Separation principle. The core idea: commands (writes that change state) and queries (reads that return data) have fundamentally different requirements, and forcing them through the same model compromises both.
CQRS in the narrow, correct sense is: the write model and the read model are separate, and they may have different shapes, different storage, and different scaling properties.
CQRS is not:
- Event sourcing. These are orthogonal. You can do CQRS without event sourcing (write model in Postgres, read model in Elasticsearch, sync via CDC). You can do event sourcing without CQRS (rare but possible). They are often combined but they are not the same thing.
- Using a read replica. A read replica is the same schema on another node. CQRS explicitly allows different schemas, different databases, even different paradigms (relational write, search read).
- Microservices. CQRS is a pattern inside or across services. It has nothing to do with service boundaries per se.
- Complicated. At its simplest, CQRS is two endpoints (POST and GET) backed by two stores that a pipeline keeps in sync. The complexity comes from what you choose to do with that freedom.
The punchy test for whether you're "doing CQRS" or just "using a read replica": are the read and write models structurally different? If the reads are denormalized, pre-joined, precomputed, or in a different engine (Elasticsearch, Redis, ClickHouse), that's CQRS. If they're the same schema with replication, that's just read scaling.
When CQRS actually wins
The interview-worthy cases:
- Read and write workloads have wildly different shapes. An e-commerce product catalog has write traffic from a few merchants and read traffic from millions of shoppers. The reads are full-text search, faceted filtering, geographic. The writes are transactional updates with inventory constraints. Jamming both through the same Postgres is a mess. CQRS with Postgres writes and Elasticsearch reads, synced via CDC, is the textbook fit.
- Complex domain logic on the write side that would poison read performance. Insurance underwriting, healthcare claim adjudication, and trading systems have write-side invariants that involve many entities, validation rules, and transactional boundaries. Querying that domain model directly for a read-heavy UI is expensive. A denormalized read model sidesteps the joins.
- Multiple read projections for different consumers. The same write model serves a customer-facing search, an internal analytics dashboard, a mobile app, and a partner API. Each wants a different shape. CQRS lets you materialize each projection independently.
- You're already event-driven. If the write side already publishes events (OrderPlaced, InventoryReserved), building read projections off those events is cheap. The event stream is the integration surface.
- Temporal queries. If queries are "show me the state at time T," an event-sourced write model plus a bitemporal read projection is the clean answer.
In the interview, justify CQRS in one of these shapes. "We'll use CQRS because search on the product catalog needs full-text and facets, and those don't belong in the transactional store" is a defensible sentence. "We'll use CQRS because it scales" is not.
The tradeoffs you need to name
CQRS has a well-known price. Name it explicitly or interviewers will assume you don't know:
- Eventual consistency between write and read. The read side lags the write side by whatever the projection pipeline latency is. Typical production systems run this at 100ms to 10 seconds. Users who wrote and immediately read can see stale data. You need a strategy: synchronous read-your-writes on the write store, session-level caching, or optimistic UI.
- Operational complexity. Two stores means two backup strategies, two monitoring dashboards, two schemas, two migration tools. Add the projection pipeline (Kafka, Debezium, a custom worker) and you have three things to keep alive.
- Schema evolution across sides. When the write schema changes, the projection logic changes, and sometimes the read schema changes. Coordinating these is harder than a single-schema migration.
- Replay and rebuild cost. When the projection logic has a bug, you need to rebuild the read model. If the write side is event-sourced, this is straightforward. If not, you need CDC from the current state, which is trickier.
- Debuggability. "Why is my data wrong" can be in the write model, in the projection, or in the read model. Three places to look instead of one.
- Developer cognitive load. New engineers don't intuit why the same data lives in two places. Onboarding cost is real.
CQRS in the wrong domain is a multiplier on complexity. CQRS in the right domain is a multiplier on clarity. The interviewer is testing which you can tell apart.
When you should NOT propose CQRS
The cases where CQRS is the wrong answer and you'll score points by refusing to suggest it:
- Simple CRUD apps. The read and write sides are the same shape. Adding CQRS doubles the moving parts for no benefit.
- Strong consistency requirements on the read path. If reads must reflect writes immediately, you need either a synchronous read-your-writes path on the write store or no split at all. CQRS adds lag by design.
- Small teams without platform engineering investment. CQRS requires infrastructure — streaming, schema registry, projection monitoring. A three-engineer team building a B2B SaaS should not start here.
- When a materialized view would do. Postgres materialized views (or incremental ones via pg_ivm) give you denormalized reads without a separate store. Same for SQL Server indexed views. Use these first before you reach for a separate engine.
- When caching solves it. If the only problem is read throughput, Redis in front of Postgres is cheaper and simpler than CQRS.
- Analytics workloads. These already go to a separate system (Snowflake, BigQuery, ClickHouse) via ETL or CDC. Don't call this CQRS; it's just operational vs analytical separation.
Real-world example: LinkedIn's Espresso + Search
LinkedIn's member and company profile data lives in Espresso (their document store). The same data, reshaped for search, lives in Galene (their search platform, originally Lucene-based). Writes go to Espresso. A pipeline produces events from Espresso's change log, projects them into Galene's search index. Reads for search come from Galene; reads for canonical profile data come from Espresso.
This is CQRS in the production sense. The write model is optimized for consistency and document retrieval by ID. The read model is optimized for full-text search with ranking. The pipeline is asynchronous, lag-monitored, and rebuildable.
Other canonical examples:
- eBay's item service. Writes to a transactional store, read projections into Solr for search, Cassandra for list views, and Redis for hot items. Multiple read models off one write model.
- Stripe's ledger. Event-sourced core ledger with CQRS-style projections into balance views, account statements, and compliance reports.
- GitHub's activity feed. Write model is commits, PRs, issues. Read model is per-user feed projections, fanned-out at write time for normal users and pulled at read time for celebrities.
- Trading systems. Order book (write side) with nanosecond consistency, reporting projections (read side) with millisecond staleness.
- EventStoreDB + a read store. The canonical CQRS + event sourcing combo, built specifically for this pattern.
Common candidate mistakes
- Proposing CQRS without justification. "We'll use CQRS" as a bullet with no tradeoff analysis is a negative signal. Always connect it to a specific workload characteristic.
- Conflating CQRS with event sourcing. These are orthogonal. Mixing them up is a tell that you read a blog post but didn't build anything.
- Ignoring the eventual consistency window. If you propose CQRS, you must address read-your-writes. A common answer: write through to both stores synchronously on the single user's session, or read from the write store for that user until the projection catches up.
- Handwaving the projection pipeline. This is the piece that fails in production. Name the tool — Debezium + Kafka, Kafka Connect, AWS DMS, a custom consumer — and the retry and DLQ strategy.
- Not mentioning rebuild. "What if the projection logic has a bug and you need to rewrite history?" You should have an answer. Event-sourced: replay. CDC-based: snapshot + catch-up. Pure dual-write: painful, don't use pure dual-write.
- Forgetting schema evolution. When events change, projections break. Name Avro/Protobuf with a schema registry.
- Picking CQRS to "scale" a toy system. Premature CQRS is premature optimization with worse debugging. Staff candidates push back on adding complexity.
Advanced follow-ups interviewers will ask
- "How do you handle read-your-writes?" Options: pin the user's reads to the write store for a short window, use a cache keyed on user+resource populated by the write, or read from the write store synchronously for that specific response.
- "What if the projection falls behind?" Monitor consumer lag, alert on breach of SLO, autoscale consumers. If the backlog is catastrophic, replay from a snapshot.
- "How do you test this?" Contract tests between write and read schemas, integration tests that assert eventual convergence, and chaos tests that break the pipeline to validate recovery.
- "What if the write side is legacy and you can't change it?" CDC off the legacy database (Debezium, Fivetran, AWS DMS) as the source for projections. Don't dual-write from the application.
- "How does this interact with microservices?" CQRS can live inside a single service (write and read model owned by one team) or span services (write in one, projection in another). The cross-service version is essentially "materialized view over someone else's event stream" and requires more governance.
- "When would you use an event-sourced write model specifically?" When the audit trail is a first-class business requirement, when temporal queries matter, or when the domain naturally speaks in events (ledgers, workflows, state machines).
- "Why not just add read replicas?" If read replicas with the same schema solve your problem, do that. CQRS is only worth it when the read model needs to be structurally different.
The staff signal in a CQRS question is the ability to say "no." Candidates who propose CQRS for every design are flashing complexity they can't justify. Candidates who propose CQRS for the catalog-search case and refuse it for the simple CRUD case are demonstrating judgment — which is the actual trait FAANG-tier interviewers are grading at the staff level.
Name the workload. Name the split. Name the price. If you can do all three in under two minutes of talking, without hand-waving the projection pipeline, you're in the top decile of candidates on this question.
Related guides
- Backend System Design Interview Cheatsheet in 2026 — Patterns, Examples, Practice Plan, and Common Traps — A backend System Design interview cheatsheet for 2026 with the core flow, architecture patterns, capacity heuristics, reliability tradeoffs, and traps that separate senior answers from vague box drawing.
- Design System Interview Guide — Tokens, Components, and Governance Questions — A practical design system interview guide covering design tokens, component APIs, accessibility, governance, adoption, contribution models, and how to answer system-maturity questions with credibility.
- Designing a Chat System Design Interview — WebSockets, Presence, and Message Storage — A system design interview guide for chat applications, covering WebSockets, fanout, message ordering, presence, storage, delivery receipts, media, search, scaling, and common trade-offs.
- Designing a Payment System Design Interview — Idempotency, Ledgers, and Reconciliation — A senior payment-system design answer lives or dies on idempotency, double-entry ledgers, and reconciliation. This guide gives the architecture, state model, failure-mode answers, and interview script.
- Designing a Search System Design Interview — Inverted Index, Ranking, and Recall — A practical system design guide for search interviews, covering inverted indexes, crawling and ingestion, query execution, ranking, recall, freshness, personalization, scaling, and evaluation trade-offs.
