Skip to content
cqrs-architecture logo

CQRS Architecture Skill

cqrs-architecture

CQRS pattern implementation and query optimization

SKILL.md

Full skill instructions

CQRS Architecture Skill

Design and implement Command Query Responsibility Segregation patterns for scalable systems.

MANDATORY: Documentation-First Approach

Before implementing CQRS:

  1. Invoke docs-management skill for CQRS patterns
  2. Verify patterns via MCP servers (perplexity, context7)
  3. Base guidance on established CQRS literature

CQRS Fundamentals

Traditional vs CQRS:

TRADITIONAL (Single Model):
┌─────────────────────────────────┐
│         Application            │
├─────────────────────────────────┤
│      Domain Model              │
│  (Reads + Writes)              │
├─────────────────────────────────┤
│         Database               │
└─────────────────────────────────┘

CQRS (Separated Models):
┌───────────────┐    ┌───────────────┐
│ Command Side  │    │  Query Side   │
│ (Write Model) │    │ (Read Model)  │
├───────────────┤    ├───────────────┤
│ Domain Logic  │    │ DTO/​Views     │
│ Aggregates    │    │ Projections   │
├───────────────┤    ├───────────────┤
│ Write DB      │───►│ Read DB       │
└───────────────┘    └───────────────┘

CQRS Levels

Level 1: Logical Separation

Same database, separate code paths:

┌─────────────────────────────────────┐
│           Application               │
├──────────────────┬──────────────────┤
│ Command Handlers │ Query Handlers   │
│ - Validation     │ - Direct SQL     │
│ - Domain Logic   │ - Projections    │
│ - Events         │ - DTOs           │
├──────────────────┴──────────────────┤
│           Single Database           │
└─────────────────────────────────────┘

Benefits:
✓ Clean separation in code
✓ Simple deployment
✓ Single source of truth
✓ Good starting point

Level 2: Separate Read Models

Same write DB, separate read DB:

┌─────────────────┐    ┌─────────────────┐
│ Command Side    │    │  Query Side     │
├─────────────────┤    ├─────────────────┤
│ Command Handler │    │ Query Handler   │
│ Domain Model    │    │ DTOs            │
├─────────────────┤    ├─────────────────┤
│ Write Database  │───►│ Read Database   │
│ (Normalized)    │sync│ (Denormalized)  │
└─────────────────┘    └─────────────────┘

Benefits:
✓ Optimized read performance
✓ Scale reads independently
✓ Different storage technologies
✓ Eventually consistent reads

Level 3: Event-Sourced CQRS

Event store as write model, projections as read:

┌─────────────────┐    ┌─────────────────┐
│ Command Side    │    │  Query Side     │
├─────────────────┤    ├─────────────────┤
│ Command Handler │    │ Query Handler   │
│ Aggregate       │    │ Read Models     │
├─────────────────┤    ├─────────────────┤
│ Event Store     │───►│ Multiple Read   │
│ (Append-only)   │    │ Databases       │
└─────────────────┘    └─────────────────┘

Benefits:
✓ Complete audit trail
✓ Temporal queries
✓ Multiple projections
✓ Rebuild read models

Command Side Design

Command Structure

// Command Definition
public record PlaceOrderCommand(
    Guid CustomerId,
    List<OrderItemDto> Items,
    string ShippingAddress
) : ICommand<OrderId>;

// Command Handler
public class PlaceOrderHandler : ICommandHandler<PlaceOrderCommand, OrderId>
{
    private readonly IOrderRepository _repository;
    private readonly IEventPublisher _events;

    public async Task<OrderId> HandleAsync(
        PlaceOrderCommand command,
        CancellationToken ct)
    {
        // Validation
        if (!command.Items.Any())
            throw new ValidationException("Order must have items");

        // Domain logic
        var order = Order.Create(
            command.CustomerId,
            command.Items.Select(i => new OrderItem(i.ProductId, i.Quantity)));

        // Persistence
        await _repository.SaveAsync(order, ct);

        // Publish events
        await _events.PublishAsync(order.GetDomainEvents(), ct);

        return order.Id;
    }
}

Command Patterns

Command Best Practices:

NAMING:
- Imperative: PlaceOrder, CancelOrder, UpdateAddress
- Include context: not just "Create" but "CreateOrder"

STRUCTURE:
- Immutable (records)
- Only data needed for operation
- No business logic in command

VALIDATION:
- Input validation in handler
- Business validation in domain
- Return meaningful errors

IDEMPOTENCY:
- Include idempotency key
- Handle duplicate submissions
- Return same result for retries

Query Side Design

Query Structure

// Query Definition
public record GetOrderByIdQuery(Guid OrderId) : IQuery<OrderDetailsDto>;

// Query Handler
public class GetOrderByIdHandler : IQueryHandler<GetOrderByIdQuery, OrderDetailsDto>
{
    private readonly IReadDbContext _db;

    public async Task<OrderDetailsDto> HandleAsync(
        GetOrderByIdQuery query,
        CancellationToken ct)
    {
        var order = await _db.OrderDetails
            .Where(o => o.OrderId == query.OrderId)
            .Select(o => new OrderDetailsDto
            {
                OrderId = o.OrderId,
                CustomerName = o.Customer.Name,
                Items = o.Items.Select(i => new OrderItemDto
                {
                    ProductName = i.ProductName,
                    Quantity = i.Quantity,
                    Price = i.Price
                }).ToList(),
                Status = o.Status,
                TotalAmount = o.TotalAmount
            })
            .FirstOrDefaultAsync(ct);

        return order ?? throw new NotFoundException("Order not found");
    }
}

Read Model Optimization

Query Optimization Strategies:

1. DENORMALIZATION
   - Pre-join data
   - Store calculated values
   - Flatten hierarchies

2. MATERIALIZED VIEWS
   - Database-managed
   - Automatically updated
   - Query-optimized

3. CACHING
   - In-memory for hot data
   - Distributed for shared
   - Invalidate on events

4. SPECIALIZED STORES
   - ElasticSearch for search
   - Redis for real-time
   - ClickHouse for analytics

Synchronization Patterns

Projection from Events

// Event-Driven Projection
public class OrderProjection : IEventHandler<OrderPlaced>, IEventHandler<OrderShipped>
{
    private readonly IOrderViewRepository _views;

    public async Task HandleAsync(OrderPlaced @event, CancellationToken ct)
    {
        var view = new OrderView
        {
            OrderId = @event.OrderId,
            CustomerId = @event.CustomerId,
            Status = "Placed",
            PlacedAt = @event.Timestamp,
            ItemCount = @event.Items.Count,
            TotalAmount = @event.TotalAmount
        };

        await _views.InsertAsync(view, ct);
    }

    public async Task HandleAsync(OrderShipped @event, CancellationToken ct)
    {
        await _views.UpdateAsync(@event.OrderId, view =>
        {
            view.Status = "Shipped";
            view.ShippedAt = @event.Timestamp;
            view.TrackingNumber = @event.TrackingNumber;
        }, ct);
    }
}

Consistency Patterns

Consistency Options:

STRONG CONSISTENCY (Same Transaction):
┌──────────┐    ┌──────────┐
│ Command  │───►│ Read     │
│ DB       │    │ Model    │
│          │    │ Update   │
└──────────┴────┴──────────┘
     Same Transaction

EVENTUAL CONSISTENCY (Async):
┌──────────┐    ┌──────────┐    ┌──────────┐
│ Command  │───►│ Message  │───►│ Read     │
│ DB       │    │ Queue    │    │ Model    │
└──────────┘    └──────────┘    └──────────┘
     Async, Eventually Consistent

HYBRID (Read-Your-Writes):
- Immediate read from command side
- Eventually consistent for others
- Version checking in queries

MediatR Implementation

Setup with MediatR

// Registration
services.AddMediatR(cfg =>
{
    cfg.RegisterServicesFromAssembly(typeof(Program).Assembly);
});

// Command/​Query Interfaces
public interface ICommand<TResult> : IRequest<TResult> { }
public interface IQuery<TResult> : IRequest<TResult> { }

// Handler Interfaces
public interface ICommandHandler<TCommand, TResult>
    : IRequestHandler<TCommand, TResult>
    where TCommand : ICommand<TResult> { }

public interface IQueryHandler<TQuery, TResult>
    : IRequestHandler<TQuery, TResult>
    where TQuery : IQuery<TResult> { }

Pipeline Behaviors

// Validation Behavior
public class ValidationBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    private readonly IEnumerable<IValidator<TRequest>> _validators;

    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken ct)
    {
        var failures = _validators
            .Select(v => v.Validate(request))
            .SelectMany(r => r.Errors)
            .Where(f => f != null)
            .ToList();

        if (failures.Any())
            throw new ValidationException(failures);

        return await next();
    }
}

// Logging Behavior
public class LoggingBehavior<TRequest, TResponse>
    : IPipelineBehavior<TRequest, TResponse>
    where TRequest : notnull
{
    private readonly ILogger<LoggingBehavior<TRequest, TResponse>> _logger;

    public async Task<TResponse> Handle(
        TRequest request,
        RequestHandlerDelegate<TResponse> next,
        CancellationToken ct)
    {
        _logger.LogInformation("Handling {RequestType}", typeof(TRequest).Name);
        var response = await next();
        _logger.LogInformation("Handled {RequestType}", typeof(TRequest).Name);
        return response;
    }
}

API Design with CQRS

REST API Pattern

[ApiController]
[Route("api/​orders")]
public class OrdersController : ControllerBase
{
    private readonly IMediator _mediator;

    // Commands use POST/​PUT/​DELETE
    [HttpPost]
    public async Task<ActionResult<OrderId>> PlaceOrder(
        [FromBody] PlaceOrderCommand command,
        CancellationToken ct)
    {
        var orderId = await _mediator.Send(command, ct);
        return CreatedAtAction(nameof(GetOrder), new { id = orderId }, orderId);
    }

    // Queries use GET
    [HttpGet("{id}")]
    public async Task<ActionResult<OrderDetailsDto>> GetOrder(
        Guid id,
        CancellationToken ct)
    {
        var order = await _mediator.Send(new GetOrderByIdQuery(id), ct);
        return Ok(order);
    }

    [HttpGet]
    public async Task<ActionResult<PagedResult<OrderSummaryDto>>> ListOrders(
        [FromQuery] ListOrdersQuery query,
        CancellationToken ct)
    {
        var orders = await _mediator.Send(query, ct);
        return Ok(orders);
    }
}

When to Use CQRS

Good Fit

CQRS Works Well For:

✓ Complex reads AND writes
  - Different optimization needs
  - Read/​write ratio imbalance

✓ Multiple views of data
  - Different query patterns
  - Multiple UI requirements

✓ Collaborative domains
  - Many concurrent users
  - Complex validation

✓ Event-driven systems
  - Microservices
  - Async processing

✓ Scalability requirements
  - Independent read/​write scaling
  - Performance optimization

Poor Fit

CQRS May Not Fit:

✗ Simple CRUD applications
  - Overhead not justified
  - Same model works fine

✗ Small team/​project
  - Added complexity
  - Maintenance burden

✗ Strong consistency required
  - Real-time requirements
  - Financial transactions

✗ Unknown query patterns
  - Ad-hoc reporting
  - BI requirements

Workflow

When implementing CQRS:

  1. Evaluate Fit: Is CQRS appropriate for this context?
  2. Choose Level: Logical, physical, or event-sourced?
  3. Design Commands: Identify write operations
  4. Design Queries: Identify read patterns
  5. Plan Sync: How will read models be updated?
  6. Implement Pipeline: Validation, logging, etc.
  7. Consider Consistency: What guarantees are needed?
  8. Test Both Sides: Command and query testing

References

For detailed guidance:


Last Updated: 2025-12-26

More skills from majiayu000

xiaohongshu logo
majiayu000/claude-arsenal

xiaohongshu

xiaohongshu

286 148
View
agent-task-conductor logo
majiayu000/claude-skill-registry

agent-task-conductor

Conduct multi-agent task orchestration and workflow coordination.

663 1
View
conductor-setup logo
majiayu000/claude-skill-registry

conductor-setup

Initialize project with Conductor artifacts (product definition,

663 1
View
animation-designer logo
majiayu000/claude-skill-registry

animation-designer

Expert in web animations, transitions, and motion design using Framer Motion and CSS

663 1
View
diagramming logo
majiayu000/claude-skill-registry

diagramming

Creates Mermaid and ASCII diagrams for flowcharts, architecture, ERDs, state machines, mindmaps, and more. Use when user mentions diagram, flowchart, mermaid, ASCII diagram, text diagram, terminal diagram, visualize, C4, mindmap, architecture diagram, sequence diagram, ERD, or needs visual docume...

663 1
View
h3-pg logo
majiayu000/claude-skill-registry-data

h3-pg

PostgreSQL bindings for H3 hexagonal grid system. Use when working with H3 cells in Postgres, including spatial indexing, geometry/geography integration, and raster analysis.

23 1
View
conductor-development logo
majiayu000/claude-skill-registry

conductor-development

Context-Driven Development skill for projects using Conductor. Use this skill when you detect a `conductor/` directory in the project, when working on tasks defined in a `plan.md` file, or when the user asks about tracks, specs, or plans. Automatically applies TDD workflow, tracks task completion...

663 1
View
conductor-status logo
majiayu000/claude-skill-registry

conductor-status

Display project status, active tracks, and next actions

663 1
View
dockerization logo
majiayu000/claude-skill-registry

dockerization

Official Stakpak application containerization standard operating procedure, a step-by-step guidline to properly dockerize applications. This is a rule book curated by the Stakpak Team.

663 1
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View