Tags: cqrs, architecture, design-pattern, commands, queries, ddd
Level: advanced
TL;DR: CQRS separates read and write operations into distinct models, allowing independent scaling, performance optimization, and tailored data schemas.
Separates methods that read data (Queries) from methods that mutate state (Commands).
Commands execute business logic and mutate state but do not return business data.
Queries return data for presentation but never modify the system state.
Enables distinct databases or schemas for reading and writing to optimize respective workloads.
Read models can be denormalized into materialized views for ultra-fast querying.
Naturally complements Event Sourcing but does not strictly require it.
Introduces eventual consistency when read and write databases are physically separated.
Q: Why would you choose CQRS over a traditional CRUD approach?R: I use CQRS when the domain is complex and the read/write workloads are highly asymmetric, allowing me to scale and optimize them independently.
Q: Do you always need two separate databases for CQRS?R: No, logical CQRS uses the same database with separate code models for commands and queries, which avoids eventual consistency overhead.
Applying CQRS to simple CRUD applications, leading to unnecessary architectural overhead.
Ignoring the UX implications of eventual consistency and failing to provide immediate UI feedback.
Using the same DTOs for both command payloads and query results.
// Command model
interface CreateOrderCommand {
type: 'CREATE_ORDER';
payload: { productId: string; quantity: number };
}
// Query model
interface GetOrderByIdQuery {
orderId: string;
}
// Command Handler (mutates state, returns void)
async function handleCreateOrder(command: CreateOrderCommand): Promise<void> {
await writeDatabase.insert(command.payload);
}
// Query Handler (reads state, no side effects)
async function handleGetOrder(query: GetOrderByIdQuery): Promise<OrderDto> {
return await readDatabase.findById(query.orderId);
}
[ ] Handling command validation failures.
[ ] Projection mechanisms for synchronizing read models.
Martin Fowler's CQRS overview
Greg Young's CQRS Documents