CQRS (Command Query Responsibility Segregation) Pattern
Learn the CQRS Pattern from a System Design perspective. Understand how CQRS separates read and write operations, improves scalability, integrates with Event Sourcing, Kafka, Spring Boot, Redis, Elasticsearch, and real-world architectures used by Amazon, Netflix, Uber, and Banking systems.
Introduction
Imagine you're designing an e-commerce platform similar to Amazon.
Daily traffic:
- 50 Million Users
- 800 Million Product Views
- 20 Million Orders
- 500 Million Product Searches
The workload is very different.
Read Operations
- Product Search
- Product Details
- Reviews
- Recommendations
- Order History
Write Operations
- Place Order
- Update Inventory
- Add Product
- Process Payment
- Cancel Order
Most applications receive 90-95% reads and only 5-10% writes.
If both reads and writes use the same database and same service,
eventually the system becomes difficult to scale.
The solution is CQRS.
Learning Objectives
After completing this article, you'll understand:
- What is CQRS?
- Why CQRS?
- Commands vs Queries
- Read Model
- Write Model
- Event Flow
- Eventual Consistency
- Kafka Integration
- Spring Boot Architecture
- Event Sourcing
- Real-world Examples
- Best Practices
What is CQRS?
CQRS stands for
Command Query Responsibility Segregation
It separates
- Write Operations (Commands)
- Read Operations (Queries)
Instead of
One Service
↓
Read
Write
CQRS creates
Write Service
↓
Database
↓
Events
↓
Read Database
↓
Read Service
Traditional Architecture
flowchart TD
USER[Users]
APP[Spring Boot]
DB[(Database)]
USER --> APP
APP --> DB
Both reads and writes share one database.
CQRS Architecture
flowchart LR
USER[Users]
CMD[Command Service]
WRITE[(Write Database)]
KAFKA[Kafka]
READ[(Read Database)]
QUERY[Query Service]
USER --> CMD
USER --> QUERY
CMD --> WRITE
WRITE --> KAFKA
KAFKA --> READ
QUERY --> READ
Reads and writes scale independently.
Command Side
Commands change data.
Examples
- Create Order
- Update Product
- Cancel Order
- Transfer Money
- Register User
Commands
Always Modify Data
Query Side
Queries never modify data.
Examples
- Search Products
- View Orders
- Get Customer
- Product Reviews
- Dashboard Reports
Queries
Read Only
Command Flow
flowchart TD
CLIENT[Client]
API[Command API]
SERVICE[Command Service]
DB[(Write Database)]
CLIENT --> API
API --> SERVICE
SERVICE --> DB
Query Flow
flowchart TD
CLIENT[Client]
API[Query API]
READ[(Read Database)]
CLIENT --> API
API --> READ
Complete CQRS Flow
sequenceDiagram
participant User
participant Command
participant WriteDB
participant Kafka
participant ReadDB
participant Query
User->>Command: Place Order
Command->>WriteDB: Save Order
WriteDB->>Kafka: OrderCreated Event
Kafka->>ReadDB: Update Read Model
User->>Query: Get Orders
Query->>ReadDB: Read Orders
Why CQRS?
Without CQRS
flowchart TD
READ[Millions of Reads]
WRITE[Thousands of Writes]
DB[(Single Database)]
READ --> DB
WRITE --> DB
Problems
- Read bottleneck
- Lock contention
- Complex indexing
- Difficult scaling
With CQRS
flowchart TD
READ[Read Traffic]
WRITE[Write Traffic]
READDB[(Read Database)]
WRITEDB[(Write Database)]
READ --> READDB
WRITE --> WRITEDB
Reads and writes no longer compete.
Read Model
Optimized for
- Fast Search
- Reporting
- Analytics
- Dashboards
Often uses
- Redis
- Elasticsearch
- OpenSearch
- MongoDB
Write Model
Optimized for
- Transactions
- ACID
- Consistency
Typically uses
- PostgreSQL
- MySQL
- Oracle
- SQL Server
Event Publishing
Whenever data changes,
an event is published.
flowchart LR
WRITE[(Write DB)]
EVENT[Order Created]
KAFKA[Kafka]
READ[(Read Model)]
WRITE --> EVENT
EVENT --> KAFKA
KAFKA --> READ
Eventual Consistency
Read Database may update slightly later.
Order Created
↓
50 ms
↓
Read Database Updated
This delay is called
Eventual Consistency.
Product Search Example
Customer
Search Laptop
Request goes directly to
Read Database
instead of transactional database.
Very fast.
Banking Example
Write Side
- Money Transfer
- Deposit
- Withdraw
Read Side
- Account Statement
- Transaction History
- Dashboard
Money transfers always use the write database.
Amazon Example
Command Side
- Place Order
- Update Inventory
- Add Product
Query Side
- Product Search
- Recommendations
- Reviews
- Order History
Netflix Example
Commands
- Watch Movie
- Update Profile
- Subscription
Queries
- Trending
- Recommendations
- Search
- Watch History
Uber Example
Commands
- Book Ride
- Cancel Ride
- Payment
Queries
- Driver Search
- Ride History
- ETA
- Fare Estimate
Event Sourcing + CQRS
Very common combination.
flowchart LR
CMD[Command]
EVENTS[Event Store]
PROJECTION[Projection]
READ[(Read Database)]
CMD --> EVENTS
EVENTS --> PROJECTION
PROJECTION --> READ
Instead of storing only current state,
every change is stored as an event.
Spring Boot Architecture
flowchart TD
CLIENT[React]
API[Spring Boot API]
CMD[Command Service]
QUERY[Query Service]
WRITE[(PostgreSQL)]
READ[(Redis/OpenSearch)]
KAFKA[Kafka]
CLIENT --> API
API --> CMD
API --> QUERY
CMD --> WRITE
WRITE --> KAFKA
KAFKA --> READ
QUERY --> READ
CQRS with Kafka
sequenceDiagram
participant Service
participant Kafka
participant Projection
participant ReadDB
Service->>Kafka: Publish Event
Kafka->>Projection: Consume Event
Projection->>ReadDB: Update Read Model
CQRS Benefits
- Independent Scaling
- Faster Reads
- Better Performance
- Better Reporting
- Different Databases
- Reduced Lock Contention
- Microservice Friendly
CQRS Challenges
- More Infrastructure
- Eventual Consistency
- Event Handling
- More Code
- More Monitoring
- Higher Operational Cost
When NOT to Use CQRS
Avoid CQRS when
- Small CRUD Applications
- Internal Tools
- Admin Panels
- Low Traffic Systems
- Simple Monoliths
Traditional CRUD is usually simpler.
When to Use CQRS
Use CQRS for
- Banking
- E-commerce
- Healthcare
- Trading Systems
- ERP
- Large SaaS Platforms
- Event-Driven Systems
- High-Traffic Applications
CQRS vs CRUD
| CRUD | CQRS |
|---|---|
| Same Model | Separate Models |
| One Database | Read & Write Databases |
| Simple | Complex |
| Small Systems | Enterprise Systems |
| Easy Maintenance | Better Scalability |
Monitoring
Monitor
- Kafka Lag
- Event Processing Time
- Read Model Delay
- Command Latency
- Query Latency
- Failed Events
- Dead Letter Queue
- Database Throughput
Tools
- Datadog
- Grafana
- Prometheus
- Kafka UI
- OpenSearch Dashboard
- CloudWatch
Common Mistakes
❌ Using CQRS for simple CRUD applications
❌ Ignoring eventual consistency
❌ No retry mechanism for events
❌ No Dead Letter Queue
❌ Updating the Read Model synchronously
❌ Large command handlers
Best Practices
- Keep Commands and Queries completely separate.
- Publish immutable events.
- Use Kafka or RabbitMQ for asynchronous communication.
- Build optimized read models.
- Monitor event lag.
- Make event consumers idempotent.
- Implement retry and Dead Letter Queue (DLQ).
- Use CQRS only when complexity is justified.
Common Interview Questions
What is CQRS?
CQRS (Command Query Responsibility Segregation) is an architectural pattern that separates write operations (commands) from read operations (queries), allowing each side to be optimized independently.
Why is CQRS used?
CQRS improves scalability, performance, and flexibility by allowing independent scaling of read and write workloads and enabling different data models for each.
Is CQRS eventually consistent?
Yes. In many implementations, the read model is updated asynchronously using events, so there can be a short delay before new data appears in read queries.
Can CQRS work without Event Sourcing?
Yes. CQRS and Event Sourcing are independent patterns. CQRS can use a traditional relational database for writes while maintaining a separate read model.
Which databases are commonly used with CQRS?
- Write Model: PostgreSQL, MySQL, Oracle, SQL Server
- Read Model: Redis, OpenSearch, Elasticsearch, MongoDB, Cassandra
Summary
CQRS is a powerful architectural pattern for enterprise applications with heavy read and write workloads. By separating commands from queries, it enables independent scaling, optimized data models, and improved application performance.
In this article, we covered:
- CQRS fundamentals
- Command and Query models
- Read vs Write databases
- Event-driven architecture
- Kafka integration
- Eventual consistency
- Event Sourcing integration
- Spring Boot architecture
- Banking, Amazon, Netflix, and Uber examples
- Monitoring
- Best practices
CQRS is especially valuable for high-scale, cloud-native, event-driven systems. When combined with Kafka, Event Sourcing, and microservices, it enables applications to process millions of transactions while maintaining high performance and scalability.
Comments
Share a question, correction, or practical insight about this article.
Checking login status...
Loading approved comments...