CQRS with Protean
Builds on DDD
This approach adds Commands, Command Handlers, and Projections on top of the DDD foundation. If you haven't read the DDD pathway yet, start there — CQRS extends those concepts.
Overview
CQRS (Command Query Responsibility Segregation) separates your application into a write side and a read side. On the write side, explicit Commands capture user intent and Command Handlers orchestrate aggregate changes. On the read side, Projections provide query-optimized views built from domain events.
This replaces Application Services with a more structured pattern: instead
of calling methods directly, the API layer submits Commands via
domain.process(), and Command Handlers execute the business logic. Events
flow to Projectors that maintain read models optimized for each query need.
Request Flow
sequenceDiagram
autonumber
participant API as API Layer
participant D as domain.process()
participant CH as Command Handler
participant R as Repository
participant Agg as Aggregate
participant EH as Event Handler
participant P as Projector
participant Proj as Projection
API->>D: Submit Command
D->>CH: Dispatch to handler
CH->>R: Load aggregate
R-->>CH: Aggregate
CH->>Agg: Invoke domain method
Agg->>Agg: Mutate state, raise event
CH->>R: Persist aggregate
R-->>EH: Domain event dispatched
EH->>EH: Handle side effects
R-->>P: Domain event dispatched
P->>Proj: Update read model
- The API layer creates a Command and submits it via
domain.process() - The framework dispatches the command to the appropriate Command Handler
- The handler loads the aggregate from the Repository
- It invokes the domain method on the aggregate
- The aggregate mutates state and raises events
- The handler persists the aggregate
- Events flow to Event Handlers for side effects and to Projectors that update read-optimized Projections
What CQRS Adds to DDD
| DDD Element | CQRS Replacement/Addition |
|---|---|
| Application Services | Commands + Command Handlers replace direct method calls |
| — | Projections provide dedicated read models |
| — | Projectors build projections from events |
| Events + Event Handlers | Same as DDD, but now also feed projectors |
| Repositories | Same as DDD |
Elements You'll Use
Everything from the DDD pathway, plus:
| Element | Purpose |
|---|---|
| Commands | Immutable DTOs representing intent to change state |
| Command Handlers | Process commands and orchestrate aggregate changes |
| Projections | Read-optimized views stored in database or cache |
| Query Handlers | Process named read intents and return projection data |
| Subscribers | Consume messages from external message brokers |
| Server | Async processing engine for events and commands |
Guided Reading Order
If you've already worked through the DDD pathway, pick up from step 4. Otherwise, start from the beginning:
Start with DDD foundations
| Step | Guide | What You'll Learn |
|---|---|---|
| 1 | Set Up the Domain | Register elements, initialize and activate your domain |
| 2 | Define Domain Elements | Aggregates, entities, value objects, fields |
| 3 | Add Rules and Behavior | Validations, invariants, mutations, raising events |
Add the command side
With the domain model in place, replace direct method calls with explicit commands that capture user intent:
| Step | Guide | What You'll Learn |
|---|---|---|
| 4 | Commands | Define commands that capture user intent |
| 5 | Command Handlers | Process commands and coordinate aggregates |
| 6 | Persist Aggregates | Save and load aggregates via repositories |
Build the read side
With commands flowing through the write path, you can define events and build query-optimized read models:
| Step | Guide | What You'll Learn |
|---|---|---|
| 7 | Events | Define domain events |
| 8 | Event Handlers | React to events for side effects and cross-aggregate sync |
| 9 | Projections | Build read-optimized views from events |
React and coordinate
To manage multi-step workflows, run asynchronous processing, and configure infrastructure:
| Step | Guide | What You'll Learn |
|---|---|---|
| 10 | Process Managers | Coordinate multi-step processes across aggregates |
| 11 | Server | Run the async processing engine |
| 12 | Configuration | Configure databases, brokers, and event stores |
| 13 | Testing | Test commands, handlers, and projections |
Relevant Patterns
These patterns complement the CQRS approach. The first group applies to any DDD project; the second group addresses concerns specific to CQRS:
| Pattern | What It Covers |
|---|---|
| Design Small Aggregates | Keep aggregates focused and performant |
| Encapsulate State Changes | Protect aggregate internals with controlled mutation |
| Replace Primitives with Value Objects | Use rich types instead of raw strings and numbers |
| Validation Layering | Apply validation at the right layer |
| Thin Handlers, Rich Domain | Keep handlers lean, push logic into the domain model |
| Testing Domain Logic in Isolation | Test domain rules without infrastructure |
| Organize by Domain Concept | Structure your project around business concepts |
| Creating Identities Early | Generate aggregate IDs before persistence |
| Command Idempotency | Ensure commands can be safely retried |
| Design Events for Consumers | Shape events around downstream needs |
| Idempotent Event Handlers | Handle duplicate events gracefully |
| Coordinating Long-Running Processes | Manage multi-step workflows with process managers |
When to Evolve to Event Sourcing
Consider moving to Event Sourcing when an aggregate meets two or more of these criteria:
- Strong auditability required — regulatory compliance or financial transactions requiring complete traceability
- Temporal analysis needed — historical reporting or state reconstruction at any point in time
- Complex state transitions — multi-step workflows with intricate business rules
- Event-driven integration — other bounded contexts consume your events as their primary data source
Note
You don't have to move your entire domain to Event Sourcing. Protean supports mixing CQRS and Event Sourcing at the aggregate level within the same domain. See the Architecture Decision guide for the full decision framework.