CacheU
High Level Design

Command Query Responsibility Segregation (CQRS)

A deep dive into the CQRS pattern — separating read and write operations, architecture, benefits, challenges, event sourcing integration, scaling strategies, and real-world distributed system examples.

Command Query Responsibility Segregation (CQRS)

Introduction: The Restaurant Kitchen Problem

Imagine a busy restaurant.

The restaurant handles two types of activities:

  1. Taking orders
  2. Serving food information to customers

These two operations are very different.

ActivityNature
Taking ordersWrites data
Showing menuReads data

Now imagine the restaurant uses one single system for both tasks.

When thousands of customers start asking for the menu while others place orders:

  • Kitchen system slows down
  • Orders take longer
  • Menu queries block order processing

This is similar to how many traditional applications work.

Both reads and writes share the same database and model.

But in real systems:

  • Reads are far more frequent than writes
  • Reads and writes have different scalability needs

To solve this problem, we use a design pattern called CQRS.


What is CQRS?

Command Query Responsibility Segregation (CQRS) is a design pattern where:

Read operations and write operations are separated into different models or services.

Instead of using one model for everything, CQRS splits the system into:

OperationPurpose
**Command**Modify data (Write)
**Query**Retrieve data (Read)

So instead of:


Application → Single Model → Database

We do:


Commands → Write Model → Write Database
Queries → Read Model → Read Database


Core Principle

CQRS is based on a simple rule:

Commands change state. Queries return state.

A command must not return data.

A query must not change state.


Example

Suppose we have an E-commerce system.

Commands

These modify system state.


CreateOrder
UpdateOrderStatus
CancelOrder
AddItemToCart

Queries

These only fetch data.


GetOrderDetails
GetUserCart
GetOrderHistory
GetProductList

Separating these operations improves performance and scalability.


Traditional CRUD Architecture

Most systems use CRUD architecture.

Diagram
flowchart LR User --> Application Application --> Database Database --> Application Application --> User

Both reads and writes hit the same database.

Problems:

ProblemExplanation
High read loadOverloads DB
Complex queriesSlow down writes
Lock contentionReduced performance
Difficult scalingReads and writes scale differently

CQRS Architecture

CQRS separates read and write paths.

Diagram
flowchart LR Client --> CommandAPI Client --> QueryAPI CommandAPI --> WriteModel WriteModel --> WriteDB QueryAPI --> ReadModel ReadModel --> ReadDB

Now reads and writes operate independently.


Command Side (Write Model)

The command side handles:

  • Business logic
  • State changes
  • Data validation
  • Transactions

Example command:

PlaceOrder

Flow:

Diagram
sequenceDiagram participant Client participant CommandHandler participant DomainModel participant WriteDB Client->>CommandHandler: PlaceOrder CommandHandler->>DomainModel: Validate DomainModel->>WriteDB: Save Order

Characteristics:

PropertyDescription
Strong consistencyRequired
TransactionalYes
Complex validationYes
Write optimizedYes

Query Side (Read Model)

The query side is optimized for fast data retrieval.

Example query:

GetOrderSummary

Flow:

Diagram
sequenceDiagram participant Client participant QueryService participant ReadDB Client->>QueryService: GetOrder QueryService->>ReadDB: Fetch Data ReadDB-->>QueryService: Response

Characteristics:

PropertyDescription
Fast readsOptimized queries
Denormalized dataPre-computed views
ScalableCan use replicas

Why Separate Read and Write Models?

Because their requirements are different.

AspectWrite ModelRead Model
ComplexityHighLow
QueriesSimpleComplex
SchemaNormalizedDenormalized
ScalingModerateMassive

Example:

Write model:

Orders
Users
Products

Read model:

UserOrderHistoryView
ProductPopularityView
DashboardMetricsView

Read models can be optimized for specific queries.


Synchronizing Read and Write Models

Since read and write models are separate, we need a way to keep them synchronized.

Common approaches:

MethodDescription
Event-driven updatesWrite model emits events
Message queuesEvents processed asynchronously
Change Data CaptureDB changes streamed

Event-Based CQRS

Most CQRS systems use events.

Example:

OrderPlaced
OrderCancelled
PaymentCompleted

Architecture:

Diagram
flowchart LR Client --> CommandService CommandService --> WriteDB WriteDB --> EventBus EventBus --> ReadModelUpdater ReadModelUpdater --> ReadDB

Process:

  1. Command modifies write DB
  2. Event published
  3. Read model updated asynchronously

Eventual Consistency

Since updates happen asynchronously:

Read models may lag slightly behind writes.

Example:

User places order.

Write DB updated instantly
Read DB updated after 100 ms

This is called:

Eventual Consistency

Most modern systems accept this tradeoff.


CQRS with Event Sourcing

CQRS is often combined with Event Sourcing.

Instead of storing current state:

We store all events that occurred.

Example event log:

OrderCreated
ItemAdded
PaymentCompleted
OrderShipped

Current state is reconstructed from events.

Architecture:

Diagram
flowchart LR Commands --> EventStore EventStore --> EventStream EventStream --> ReadModel

Benefits:

BenefitExplanation
Audit logFull history
DebuggingReplay events
ScalabilityAppend-only writes

Read Model Optimization

Read databases can be optimized differently.

Examples:

TechnologyUse Case
ElasticsearchSearch queries
RedisFast cache reads
CassandraLarge-scale analytics
SQL replicasReporting

Example:

Diagram
flowchart LR EventBus --> Redis EventBus --> ElasticSearch EventBus --> SQLReplica

Each optimized for specific queries.


Scaling CQRS

CQRS scales extremely well.

Write Scaling

Sharded write database

Read Scaling

Multiple read replicas

Architecture:

Diagram
flowchart LR Users --> QueryService QueryService --> ReadReplica1 QueryService --> ReadReplica2 QueryService --> ReadReplica3

Reads can scale horizontally.


Real-World Example: E-Commerce

In a large e-commerce platform:

Daily traffic:

Reads → 1 billion
Writes → 10 million

Ratio:

100:1

If reads and writes share one database:

System becomes slow.

CQRS allows:

  • Write DB optimized for transactions
  • Read DB optimized for queries

CQRS in Microservices

CQRS works extremely well with microservices.

Example architecture:

Diagram
flowchart LR UserService --> EventBus OrderService --> EventBus PaymentService --> EventBus EventBus --> AnalyticsService EventBus --> RecommendationService

Services emit events.

Read models consume them.


Advantages of CQRS

AdvantageExplanation
Independent scalingReads and writes scale separately
PerformanceOptimized queries
FlexibilityMultiple read models
Better domain modelingClear separation
High scalabilityHandles massive traffic

Challenges of CQRS

ChallengeExplanation
Increased complexityMore components
Eventual consistencyData delay
Data duplicationMultiple read models
Debugging difficultyDistributed flow

CQRS is powerful but not suitable for every system.


When to Use CQRS

Use CQRS when:

ScenarioReason
Read-heavy systemsOptimize queries
Large-scale systemsSeparate scaling
Complex domainsRich business logic
Event-driven architecturesNatural integration

When NOT to Use CQRS

Avoid CQRS if:

ScenarioReason
Small applicationsOverkill
Simple CRUD appsUnnecessary complexity
Low traffic systemsNo benefit

Real-World Systems Using CQRS

Large tech companies use CQRS patterns.

Examples:

CompanyUsage
NetflixEvent-driven microservices
AmazonOrder processing
LinkedInActivity feeds
UberTrip processing

These systems process millions of events per second.


CQRS vs Traditional Architecture

FeatureTraditionalCQRS
ModelSingleSeparate
ScalingLimitedIndependent
ComplexityLowHigher
PerformanceModerateHigh

Interview Questions

What is CQRS?

A design pattern that separates read operations (queries) from write operations (commands).


Why use CQRS?

To:

  • Improve scalability
  • Optimize read performance
  • Handle complex domains

What is Eventual Consistency?

When read models update asynchronously after writes.


How does CQRS scale?

Reads and writes scale independently using different databases and services.


Key Takeaways

ConceptExplanation
CQRSSeparate read and write models
CommandOperation that modifies state
QueryOperation that retrieves data
Event-driven updatesSynchronize read models
Eventual consistencyDelayed read updates

Final Analogy

Think of CQRS like a library system.

Writing books

Authors update books.

Write Model

Reading books

Millions of readers access copies.

Read Model

Instead of giving readers the original manuscript, libraries distribute optimized copies.

This allows millions of readers without slowing down the authors.


Conclusion

Command Query Responsibility Segregation is one of the most powerful patterns in High Level Design and distributed systems.

It allows systems to:

  • Scale reads independently
  • Handle massive workloads
  • Optimize data access patterns
  • Integrate seamlessly with event-driven architectures

However, CQRS introduces complexity and should be used when the benefits outweigh the cost.

In large-scale systems handling millions of requests per second, CQRS becomes an essential architectural tool.