Skip to main content
SDMastery
advanced11 min readUpdated 2026-06-08

CQRS

CQRS separates read and write models so each can be optimized independently — write to a normalized database, read from a denormalized projection.

Diagram showing the key components and data flow in a CQRS system design
High-level overview of CQRS
CQRS

CQRS (Command Query Responsibility Segregation) splits a system into two sides: commands that change state and queries that read state. Each side gets its own data model, optimized for its purpose. The write side uses a normalized model for consistency; the read side uses denormalized projections for fast queries. This pattern shines in systems where read and write workloads have vastly different characteristics — like an e-commerce site where product catalog reads outnumber order writes 1000:1.

AspectDetails
What it isA pattern that uses separate models for reading and writing data, allowing each to be optimized independently
When to useSystems with asymmetric read/write ratios, complex queries on write-heavy data, or when read and write scaling needs differ
When NOT to useSimple CRUD apps where reads and writes use the same model — CQRS adds complexity without benefit in these cases
Real-world exampleMicrosoft uses CQRS in Azure DevOps to serve billions of read queries from denormalized projections while writes go to a normalized event store
Interview tipPair CQRS with event sourcing — interviewers often ask about both together, and explaining eventual consistency between read/write models shows depth
Common mistakeExpecting immediate consistency between write and read sides — the read model is asynchronously updated, so queries may return stale data briefly
Key tradeoffScalability and query performance vs complexity and eventual consistency between the two models

Why This Matters

In traditional architectures, one model serves both reads and writes. This forces a compromise: normalize for write consistency or denormalize for read performance. CQRS eliminates this tradeoff. You can write to a normalized PostgreSQL database for ACID guarantees while serving reads from a denormalized Elasticsearch index or Redis cache. Each side scales independently. The read model is rebuilt from events, so you can create multiple projections optimized for different query patterns without touching the write side.

System architecture diagram for CQRS showing how services, databases, and caches connect
System architecture for CQRS

The Building Blocks

  • Command Model: Handles writes: validates business rules, persists state changes. Optimized for consistency — normalized, ACID-compliant. Rejects invalid mutations.
  • Query Model: Handles reads: serves precomputed, denormalized views. Optimized for speed — flat tables, materialized views, search indexes. No business logic.
  • Event Bus: Connects write to read side. After a command succeeds, an event is published. Read model projectors consume events and update denormalized views asynchronously.
  • Projectors: Event handlers that transform domain events into read model updates. One event can update multiple projections (e.g., order-placed updates inventory view AND revenue dashboard).
  • Eventual Consistency: The read model lags behind the write model by the event propagation delay (typically milliseconds). Queries may return slightly stale data.

Under the Hood

When a user places an order, the command handler validates the request (inventory check, payment authorization), writes to the orders table, and publishes an OrderPlaced event. The read-side projector receives the event and updates multiple views: the user's order history (denormalized with product names and images), the admin dashboard (aggregated revenue), and the inventory count (decremented).

Step-by-step diagram showing how CQRS processes a request from start to finish
How CQRS works step by step

The command model uses a normalized relational schema: separate orders, order_items, products, and users tables with foreign keys. The query model uses denormalized documents: a single order_summary collection with all data embedded. This means reads avoid JOIN queries entirely — a single document fetch returns everything the UI needs.

The key architectural decision is the projection mechanism. Synchronous projection (update read model in the same transaction as the write) provides strong consistency but couples the models. Asynchronous projection (via message queue) decouples them and allows independent scaling, but introduces eventual consistency. Most production CQRS systems use asynchronous projection with sub-second lag.

How Companies Actually Do This

Microsoft uses CQRS extensively in Azure DevOps. The write side stores work items in a normalized SQL database, while the read side serves queries from denormalized projections, handling billions of reads per day.

Comparison table for CQRS contrasting approaches, tradeoffs, and when to use each
Comparing key aspects of CQRS

Walmart implemented CQRS for their product catalog. Writes (price updates, inventory changes) go to a normalized database, while the shopping UI reads from Elasticsearch projections for sub-50ms query responses.

Netflix uses a CQRS-like pattern for their content catalog. Metadata writes go to a primary store, while multiple read-optimized projections serve different clients (TV, mobile, web) with different data shapes.

Common Pitfalls

  1. Applying CQRS to simple CRUD applications where the same model works for both reads and writes — the added complexity is not justified
  2. Not handling projection failures — if a projector crashes, the read model becomes stale. You need replay capability to rebuild projections from events
  3. Ignoring the eventual consistency gap — users who create an entity and immediately query for it may not see it if the projection hasn't caught up yet
Data flow diagram for CQRS showing how requests and responses move through the system
Data flow through CQRS

Interview Questions Worth Practicing

  1. When would you choose CQRS over a traditional CRUD architecture, and what complexity does it add?
  2. How do you handle the eventual consistency between write and read models in a CQRS system?
  3. How would you rebuild a corrupted read model projection from scratch?

The Tradeoffs

  • Query Performance vs Complexity: Denormalized read models eliminate JOINs and serve queries in O(1), but maintaining projectors and handling consistency adds significant system complexity.
  • Independent Scaling vs Operational Cost: Read and write sides can scale separately (e.g., 10 read replicas, 1 write database), but you now operate two data stores and a message bus.
  • Flexibility vs Consistency: Multiple read projections serve different query patterns perfectly, but all lag behind the write model, requiring careful UX design for the consistency gap.
Component diagram for CQRS showing each building block and its responsibility
Key components of CQRS

How to Explain This in an Interview

Here is how I would explain CQRS in a system design interview:

CQRS separates the system into command (write) and query (read) sides, each with its own optimized data model. I would use it when read and write patterns are fundamentally different — for example, an e-commerce site where writes are normalized for ACID (orders, inventory) but reads need denormalized documents (product pages with embedded reviews, ratings, pricing). The write side publishes events to a message queue, and read-side projectors build denormalized views. Each side scales independently. The main tradeoff is eventual consistency — after a write, the read model takes milliseconds to catch up. I handle this with optimistic UI updates on the client and always reading from the write model for just-created entities.

Interview preparation checklist for CQRS with key points to mention and mistakes to avoid
Interview tips for CQRS

The Real-World Incident That Made This Famous

Understanding CQRS became critical after multiple high-profile production incidents at major tech companies. When systems handle millions of users, even small misunderstandings about CQRS can lead to cascading failures that cost millions in lost revenue and erode user trust. Companies like Netflix, Google, Amazon, and Meta have all invested heavily in mastering CQRS because they learned the hard way that ignoring it leads to outages.

The key lesson from these incidents: CQRS is not just a theoretical concept — it is a practical skill that separates engineers who build resilient systems from those who build fragile ones. Every major outage report from the past decade involves at least one CQRS-related design decision that was either implemented incorrectly or overlooked entirely during the initial architecture review.

Decision guide for when to choose CQRS and when alternative approaches are better
When to use CQRS

How Senior Engineers Think About This

Senior engineers approach CQRS differently from textbook definitions. Instead of memorizing rules, they build mental models. They ask: "What problem does CQRS solve? When does it fail? What are the alternatives?" This problem-first thinking leads to better design decisions because every system has unique constraints.

When evaluating CQRS in a system design context, experienced engineers consider the failure modes first. What happens when this component goes down? How does the system degrade? Is the degradation graceful or catastrophic? These questions reveal more about your understanding than any textbook definition.

The key difference between junior and senior engineers when it comes to CQRS: juniors focus on the happy path, while seniors design for what happens when things go wrong. They consider operational cost, team expertise, monitoring requirements, and how the decision will look six months from now when traffic has grown 10x.

Tradeoff analysis for CQRS listing advantages, disadvantages, and real-world considerations
Advantages and disadvantages of CQRS

Common Interview Mistakes

Mistake 1: Giving a textbook definition without context. Interviewers want to see you connect CQRS to real systems and real problems. Instead of reciting definitions, explain when and why you would use CQRS in the system you are designing.

Mistake 2: Not discussing trade-offs. Every design decision involving CQRS has trade-offs. Discuss what you gain and what you give up. Acknowledge the downsides and explain why the benefits outweigh them for your specific use case.

Mistake 3: Overcomplicating the solution. Start with the simplest approach to CQRS that meets the requirements, then add complexity only when justified. Many candidates jump to complex implementations when a simpler solution would work perfectly.

Production deployment examples of CQRS at companies like Netflix, Google, and Amazon
Real-world examples of CQRS

Production Checklist

  • Define clear metrics for measuring the effectiveness of your CQRS implementation
  • Set up monitoring and alerting that specifically tracks CQRS-related failures
  • Document your CQRS design decisions in Architecture Decision Records (ADRs)
  • Test failure scenarios related to CQRS in staging before production deployment
  • Review and update your CQRS implementation quarterly as system requirements evolve
  • Train new team members on the specific CQRS patterns used in your system
  • Establish runbooks for common CQRS-related incidents and recovery procedures

Practical Implementation for .NET Developers

In .NET, use MediatR for the command/query separation: IRequest<T> for commands, IRequest<TResponse> for queries, with separate handler classes. For event projection, use MassTransit consumers that listen to RabbitMQ/Azure Service Bus events and update read-side EF Core DbContexts or Elasticsearch indexes. The Marten library provides built-in CQRS and event sourcing with PostgreSQL as both the event store and projection target.

ASP.NET Core setup: Create a service class that encapsulates the logic, register it with dependency injection, and inject it into your controllers or minimal API endpoints. The built-in DI container handles lifecycle management.

Entity Framework Core: For database interactions, EF Core provides the ORM layer. Use migrations for schema management and raw SQL for performance-critical queries. Consider Dapper for read-heavy paths where EF Core overhead matters.

Azure integration: If deploying to Azure, leverage managed services — Azure Cache for Redis, Azure SQL, Azure Service Bus, Azure Cosmos DB. These eliminate operational overhead and provide built-in monitoring through Application Insights.

Testing: Use xUnit with Testcontainers for integration tests that spin up real databases in Docker. Mock external dependencies with NSubstitute. The WebApplicationFactory class lets you test your entire HTTP pipeline in-process.

Monitoring: Add Application Insights telemetry to track request latency, dependency calls, and custom metrics. Use structured logging with Serilog to make production debugging possible:

text
Log.Information("Processing {Operation} for {ResourceId}", operation, resourceId);

This gives you searchable, structured logs in Azure Monitor or Seq.