← Home
🏗Crack System Design with DSA AnimatorSystem DesignNEW
🏗 System Design›Architecture Styles

🧩CQRS Pattern

Separate write and read models to optimize each side independently.

📌 Key IdeaCQRS (Command Query Responsibility Segregation) splits command and query models. Writes enforce domain rules; reads use denormalized projections. It improves scalability and clarity in complex domains but adds eventual consistency and operational overhead.
🧩

Problem it solves

  • One shared CRUD model often becomes a compromise between write correctness and read performance.
  • Complex queries can pollute domain models and slow down transactional paths.
  • CQRS separates command and query concerns so each side can be designed and scaled for its own purpose.
📖

Definition

In CQRS, command side handles state-changing operations and invariants; query side serves read-optimized views. Both models can have different data structures and scaling strategies.

✨

Why It Matters

  • Read and write workloads often have different access patterns.
  • Read models can be optimized without polluting write-domain logic.
  • Supports high-scale APIs where query traffic dominates writes.
✅

When to Use

  • Complex domains with heavy reads and comparatively fewer writes.
  • Need for specialized query models (dashboards/reporting/search views).
  • Teams comfortable operating async pipelines and projection lag.
🚫

When NOT to Use

  • Simple CRUD apps with low scale and straightforward queries.
  • Teams not ready for eventual consistency debugging and replay tooling.
💻

Code Variations

1️⃣ Command side sketchjava
public void handle(PlaceOrderCommand cmd) {
  Order order = orderRepo.load(cmd.orderId());
  order.place(cmd.items());          // domain rules enforced here
  orderRepo.save(order);
  eventBus.publish(new OrderPlaced(cmd.orderId(), cmd.items()));
}
2️⃣ Query projection updatejava
@EventListener
public void on(OrderPlaced e) {
  orderReadRepo.upsert(new OrderSummaryView(
      e.orderId(), "PLACED", e.items().size()
  ));
}
Read side can use denormalized schema for fast API responses.
3️⃣ Query endpoint (read model only)java
@GetMapping("/orders/{id}")
public OrderSummaryView get(@PathVariable String id) {
  return orderReadRepo.findById(id)
      .orElseThrow(() -> new NotFoundException("order not found"));
}
📊

Traditional CRUD vs CQRS

AspectTraditional CRUDCQRS
ModelSingle shared modelSeparate command/query models
Read optimizationLimited by write model shapeDedicated projections for query speed
ConsistencyUsually immediate in one DB txOften eventual between write and read model
ComplexityLowerHigher (projections, sync, tooling)
🔀

Common Confusions Cleared Up

CQRS is independent of Event Sourcing

You can implement CQRS without event sourcing (using normal DB writes + change events). Event sourcing is a persistence strategy, not a mandatory CQRS requirement.

Eventual consistency is a product decision

If read model lags write model, user may not see latest state instantly. UX and API contracts should communicate pending states.

⚠️

Common Mistakes / Anti-Patterns

  • Introducing CQRS before proving read/write divergence.
  • No replay/rebuild strategy for corrupted read projections.
  • Using synchronous cross-service calls in every projection update.
🎤

Interview Q&A

🧾

Quick Cheat Sheet

Command sideValidates and changes domain state.
Query sideServes denormalized read views.
Trade-offPerformance/scalability vs operational complexity.
Design keyPlan for projection lag and rebuilds.
🔗

Related Topics