CQRS Overview
Command Query Responsibility Segregation (CQRS) separates the write model (how you change data) from the read model (how you query data). Event sourcing and CQRS complement each other naturally.
The Split
Write side: Commands validate against the aggregate and produce events. The aggregate enforces business rules.
Read side: Projections consume events and build optimised views for queries. Each projection can structure data however the UI needs.
Why Separate?
| Concern | Write Model | Read Model |
|---|---|---|
| Optimised for | Consistency, validation | Query performance |
| Structure | Reflects domain behaviour | Reflects UI needs |
| Updates | Transactional | Eventually consistent |
| Scaling | Consistent writes | Replicated reads |
A single aggregate might feed multiple projections (account summary, transaction history, fraud detection, analytics). Each projection sees the same events but builds a different view.
In This Crate
The crate models CQRS through:
Aggregate+Handle<C>— the write sideProjection+ApplyProjection<E>— the read sideRepository— orchestrates both
// Write: execute a command
repository
.execute_command::<Account, Deposit>(&id, &command, &metadata)
.await?;
// Read: load a projection
let summary = repository
.load_projection::<AccountSummary>(&())
.await?;
Eventual Consistency
With CQRS, read models may not immediately reflect the latest write. This is fine for most UIs—users expect slight delays. For operations requiring strong consistency, read from the aggregate itself (via repo.load()).
Next
Architecture — How the components fit together