Your Read Model Does Not Need Your Domain Model

Your domain model contains everything needed to protect business rules.

Your API needs five fields.

Do you really need to load the entire aggregate to return those fields?

Not necessarily.

Commands and queries have different responsibilities.

Your Read Model Does Not Need Your Domain Model

1. Your domain model protects invariants

Consider an Order aggregate:

Order
 ├── Customer
 ├── OrderItems
 ├── Payments
 ├── Discounts
 ├── Shipping
 └── Business Rules

The model exists to ensure valid state transitions.

It might enforce rules such as:

An order cannot be paid twice.

A canceled order cannot be shipped.

Discounts must satisfy eligibility rules.

Those responsibilities matter when changing the order.

They might not matter when displaying an order summary.

2. Queries need data, not behavior

Imagine a dashboard that needs:

{
  "orderId": 123,
  "customerName": "Alex",
  "total": 149.99,
  "status": "Paid"
}

Instead of reconstructing the full aggregate, a query can return a projection:

SELECT
    o.Id AS OrderId,
    c.Name AS CustomerName,
    o.Total,
    o.Status
FROM Orders o
JOIN Customers c ON c.Id = o.CustomerId
WHERE o.Id = 123;

The query returns the data required by the consumer.

No domain aggregate reconstruction is necessary.

3. Separate responsibilities without overengineering

CQRS doesn't require separate databases, event sourcing, or additional microservices.

You can separate commands and queries inside the same application.

Commands use domain models to enforce business rules.

Queries use projections optimized for their consumers.

If a read operation doesn't need domain behavior, it doesn't need to load that behavior.