Two Common CQRS Design Approaches and How to Choose the Right One

The article compares the classic Event Sourcing + CQRS architecture with the more engineering‑focused read‑write separation CQRS, outlining their workflows, advantages, drawbacks, and guiding criteria for selecting the appropriate design in real‑world projects.

AI Skills Research
AI Skills Research
AI Skills Research
Two Common CQRS Design Approaches and How to Choose the Right One

When studying Domain‑Driven Design (DDD) material, CQRS (Command Query Responsibility Segregation) often appears alongside concepts such as Event Sourcing, Outbox, and eventual consistency, which can be confusing. This article clarifies the two most common CQRS design styles and explains how to pick the right one for a project.

Version 1: Event Sourcing + CQRS (the most discussed version)

img
img

The diagram shows the typical flow:

Client sends a Command request to the Command Service.

Command Service executes the Aggregate, produces a Domain Event, and writes it to the Event Store.

The Domain Event is published to the Event Bus.

Query Service subscribes to the Event Bus and receives the Domain Event.

Query Service updates the read‑model database.

Event Sourcing basics

The database stores only Domain Events, not the current domain state.

Because an Aggregate’s changes generate Domain Events, the event stream can reconstruct the final state.

Benefits of Event Sourcing

Complete event archive enables restoration to any point in time.

Full change history aids troubleshooting.

Reduces “dual‑write” inconsistency; events are the source of truth.

Append‑only writes lower write‑conflict complexity (though duplicate and idempotent handling remain).

Note: the third benefit can also be achieved in non‑ES systems with a transactional outbox.

Why CQRS appears

Replaying events for every query is costly, so CQRS separates reads.

In most systems, query frequency far exceeds command frequency, so a dedicated read model improves performance.

Problems of this version

Write service does not store the final object state, making “read‑then‑write” decisions complex and introducing read‑write latency.

Higher storage and operational costs due to event volume, replay, snapshot and archiving strategies.

Event model evolution is difficult; schema changes require handling historic events, replay logic, and query projections.

Data synchronization is eventually consistent, not strongly consistent.

Transaction boundaries and failure compensation become complex (publish failures, duplicate consumption, ordering, idempotency).

Version 2: Read‑Write Separation (practical engineering CQRS)

img
img

This approach splits the model into two responsibilities.

Write : DDD handles business rules, state changes, and persistence.

Query : Optimized for UI and reporting needs, providing high‑performance, customizable queries.

Reason for separation:

Aggregate models are not naturally suited for query scenarios; they have high query cost and field structures may not match front‑end requirements.

Advantages of this design

Clear responsibility boundaries make it obvious which operations are commands and which are queries, reducing accidental data modifications during queries.

Model decoupling prevents polluting the Aggregate for query convenience, adhering to the single‑responsibility principle.

Supports physical isolation and heterogeneous storage, e.g., writes to MySQL and queries from PostgreSQL or Elasticsearch.

The author uses this pattern in projects; similar practices are mentioned by Amichai Mantinband in “Understand Clean Architecture in 7 Minutes”.

img
img
img
img

Conclusion

Most teams adopt the read‑write separation version of CQRS first, rather than the full Event Sourcing + CQRS stack.

Event Sourcing + CQRS is suitable when there is a strong need for audit trails, replayability, point‑in‑time recovery, and the team has the engineering capability to handle event modeling, projection building, idempotent consumption, and event version evolution, and when the business complexity justifies the architectural cost.

If the goal is clear system boundaries, better query performance, and cleaner code responsibilities, starting with read‑write separation is usually the safer choice.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ArchitectureDomain-Driven DesignCQRSEvent SourcingRead Model
AI Skills Research
Written by

AI Skills Research

Fearlessly forging ahead, constantly growing.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.