CQRS (Command Query Responsibility Segregation) is a design pattern that splits the model used to write data from the model used to read data. In a classic CRUD system the same object handles both commands (create, update, delete) and queries (select). CQRS replaces that single model with two distinct paths: a command side that validates intent and mutates state, and a query side that serves optimized read models.
Why split reads and writes?
- Performance – Reads can be tuned for speed (e.g., denormalized tables, caches) without worrying about write‑side constraints.
- Scalability – Write traffic and read traffic often have different scaling characteristics. You can scale each side independently.
- Security & Simplicity – Commands enforce business rules; queries can be made read‑only, reducing accidental mutation.
- Evolution – The read model can evolve faster because it isn’t tied to the write schema.
The trade‑offs include added complexity, eventual consistency, and the need for message transport (queues, event buses). In many teams the overhead is justified only when read/write load is high or the domain is complex.
How does event sourcing fit?
Event sourcing records every state‑changing event instead of persisting the current state. When combined with CQRS:
- Command side emits an event after validation.
- Event store persists the immutable event stream.
- Projection handlers consume events to build one or more read models.
This pairing gives you an audit trail and makes rebuilding read models trivial. However, you now need to manage versioning of events and handle replay performance.
Typical interview progression
| Level | Core question | Sample spoken answer (45‑90 s) | Likely follow‑up |
|---|---|---|---|
| Junior | "What is CQRS?" | "CQRS stands for Command‑Query Responsibility Segregation. It separates the part of the system that handles commands—operations that change state—from the part that handles queries—operations that only read data. This lets us optimize each side independently and keep business rules in one place." | "When would you choose CQRS over a simple CRUD approach?" |
| Mid | "What are the main benefits of CQRS?" | "The biggest benefits are performance and scalability. Because reads don’t have to go through the same model that validates writes, we can use read‑optimized tables or caches. It also lets us scale the write side and read side on different resources, and it isolates business logic to the command side, making it easier to test and secure." | "What are the downsides you’ve seen in production?" |
| Senior | "How do you handle eventual consistency between the command and query sides?" | "We accept that the read model may lag behind the write model by a few milliseconds to seconds. To keep the UI consistent we either show a loading indicator or use optimistic UI updates that are reconciled when the eventual read arrives. In critical paths we can use a synchronous read‑through cache or a materialized view that updates in the same transaction, but that adds latency to the command side." | "Can you walk me through a concrete CQRS implementation you built?" |
| Lead | "Explain how you would migrate an existing monolithic CRUD service to CQRS." | "First I’d identify high‑traffic read scenarios and extract them into separate query handlers backed by denormalized tables. Then I’d introduce a command layer that validates intent and publishes events. Finally, I’d build projection services that listen to those events and keep the read tables in sync. Throughout the migration I’d keep both models running side‑by‑side and use feature flags to switch traffic gradually." | "How do you test the consistency guarantees during the migration?" |
Sample senior‑level answer
Question: *"How does CQRS help with domain complexity?"
Answer:
"When a domain has many business rules, a single CRUD model tends to become a tangled mess of validation logic spread across repositories, services, and UI code. CQRS forces a clean separation: the command side becomes the sole place where we enforce invariants, so every state change passes through a single, well‑tested path. The query side can then be built purely for consumption, using read‑optimized projections that reflect the current state without any extra rules. This separation makes the codebase easier to reason about, and it also lets us evolve the read model—adding new reports or dashboards—without risking regressions in the core business logic. In practice I’ve seen teams cut the defect rate on critical workflows by more than half after moving to CQRS because the validation layer became much more deterministic."
Typical follow‑up: "What challenges did you face when you introduced eventual consistency?"
Concrete code snippet (C# example)
// Command handler
public class CreateOrderHandler : ICommandHandler<CreateOrder>
{
private readonly IEventStore _store;
public async Task HandleAsync(CreateOrder cmd)
{
// Validate business rules
if (cmd.Quantity <= 0) throw new InvalidOperationException("Qty must be >0");
var @event = new OrderCreated(cmd.OrderId, cmd.ProductId, cmd.Quantity);
await _store.AppendAsync(@event);
}
}
// Projection (read model)
public class OrderProjection : IEventHandler<OrderCreated>
{
private readonly IReadRepository _readRepo;
public async Task HandleAsync(OrderCreated ev)
{
var dto = new OrderDto { Id = ev.OrderId, Product = ev.ProductId, Qty = ev.Quantity };
await _readRepo.InsertAsync(dto); // denormalized table for fast reads
}
}
The command validates and emits an event; the projection consumes the event and updates a read‑optimized table. A UI component would query the OrderDto directly, bypassing any domain logic.
When not to use CQRS
- Low traffic applications where the added infrastructure (message bus, event store) outweighs benefits.
- Simple domains with minimal business rules; a clean CRUD service may be sufficient.
- Teams without experience in asynchronous patterns; the learning curve can introduce bugs.
If you’re unsure, start by extracting a single read‑heavy query into its own view and see if the performance gain justifies the extra code.
How to practice this
- Pick a familiar CRUD endpoint (e.g., a ticket‑creation API). Refactor it into a command that publishes an event and a separate query that reads from a denormalized table.
- Record yourself answering a CQRS question aloud. Use Call Assistant to capture the answer and get a quick feedback loop on clarity and pacing.
- Simulate a follow‑up by having a colleague ask a deeper question. Practice extending your story while keeping the core explanation anchored in your resume projects.
FAQ
- Q: Is CQRS the same as Event Sourcing? A: No. CQRS is about separating read and write models; event sourcing is a way to store state changes as events. They often complement each other but can be used independently.
- Q: Do I need a separate database for the query side? A: Not always. You can use the same physical database with separate tables or schemas, but many teams choose a different store (e.g., a NoSQL cache) for performance.
- Q: How do I test eventual consistency? A: Write integration tests that issue a command, then poll the query side until the expected projection appears, asserting the delay is within acceptable bounds.
- Q: Can CQRS work with GraphQL? A: Yes. The query resolvers can fetch from the read model, while mutations act as commands that emit events.
Frequently asked questions
Is CQRS the same as Event Sourcing?
No. CQRS separates read and write models; event sourcing records every state‑changing event. They often pair together but can be used separately.
Do I need a separate database for the query side?
Not necessarily. You can use separate tables or schemas within the same DB, or choose a different store like a cache for faster reads.
How do I test eventual consistency?
Create integration tests that send a command, then poll the query side until the projected data appears, verifying the latency stays within your SLA.
Can CQRS work with GraphQL?
Yes. GraphQL queries can resolve against the read model, while mutations act as commands that publish events to update the write side.
#concept questions#CQRS#software architecture#interview prep#design patterns