---
title: "CQRS"
type: "architectural-pattern"
slug: "cqrs"
url: "http://localhost:3000/en/architectural-patterns/cqrs.md"
also_known_as: "Command Query Responsibility Segregation"
description: "Separate the model that changes state (commands) from the model that reads state (queries), so each side can be modeled, scaled and optimized independently."
languages: ["typescript"]
---
# CQRS

_Also known as: Command Query Responsibility Segregation_

> Separate the model that changes state (commands) from the model that reads state (queries), so each side can be modeled, scaled and optimized independently.

## Intent

Use one model to update information and a different model to read it. Commands express intent to change state; queries return data shaped for display. The two no longer have to compromise on a single shared representation.

## Problem

In a traditional design, one model serves both writes and reads. Writes need rich validation and invariants; reads need denormalized, display-ready shapes — often many different ones for different screens and reports.

Forcing both through the same objects and tables leads to awkward compromises: over-fetching, complex ORM mappings, lock contention, and a model that is good at neither job.

## Solution

CQRS splits the system in two. The **write side** handles _commands_ through handlers that load an aggregate, enforce invariants and persist the change (optionally emitting events). The **read side** serves _queries_ from one or more _read models_ shaped specifically for the views that consume them.

The two sides can share a database or use separate stores. When they are separate, read models are kept up to date by projecting the write side’s events, accepting _eventual consistency_ in exchange for independent scaling and simpler queries.

## Structure

* **Command** — a request to change state, named for intent (`PlaceOrder`).
* **Command handler** — validates and applies the command to the write model.
* **Write model** — aggregates that enforce invariants; may emit **events**.
* **Read model / projection** — denormalized views built for queries, updated from events.
* **Query** & **query handler** — read-only requests served from the read model.

## Applicability

* Use it where **reads and writes have very different shapes or loads** — many read views, heavy reporting, or a high read-to-write ratio.
* Use it for **task-based UIs** and collaborative domains, where it pairs naturally with Domain-Driven Design and event sourcing.
* **Avoid it** for simple CRUD; a single model is simpler and the split adds cost without payoff.

## How to Implement

1. Model **commands** as explicit intentions rather than generic updates.
2. Route each command to a **handler** that loads the relevant aggregate and enforces its invariants.
3. Persist the change and, if using events, **publish** what happened.
4. Build **read models** tailored to your views; if separated, update them by projecting events.
5. Serve **queries** directly from the read models — no domain logic on the read side.

## Pros

* Read and write sides can be modeled, optimized and scaled independently.
* Each model stays small and focused on one job.
* Fits task-based UIs and composes well with event sourcing and DDD.
* Read models can be tailored per view, eliminating awkward joins.

## Cons

* More moving parts and more code than a single CRUD model.
* Separate read stores introduce eventual consistency, which the UX must handle.
* Easy to over-engineer; rarely justified for simple domains.
* Operational overhead of projections and message plumbing.
## Relations

**Related patterns**

- [Domain-Driven Design](/en/architectural-patterns/domain-driven-design.md)

## Code Examples

### typescript

```typescript
// Write side: a command and its handler.
type PlaceOrder = { orderId: string; sku: string; qty: number }

class PlaceOrderHandler {
  constructor(private orders: OrderRepository) {}
  async handle(cmd: PlaceOrder) {
    const order = new Order(cmd.orderId)
    order.addLine(cmd.sku, cmd.qty)
    await this.orders.save(order) // emits OrderPlaced
  }
}

// Read side: a query served from a denormalized view.
type GetOrderSummary = { orderId: string }

class GetOrderSummaryHandler {
  constructor(private views: OrderSummaryView) {}
  handle(q: GetOrderSummary) {
    return this.views.byId(q.orderId) // pre-shaped for the screen
  }
}
```

