Skip to content
Back to blog
Event SourcingCQRSMicroservicesArchitectureDDD

Event Sourcing vs CQRS

July 4, 202611 min read

Event Sourcing and CQRS are two patterns that often appear together in microservices and domain-driven design — but they solve different problems. Event Sourcing stores state as a sequence of domain events instead of updating rows in place — giving you a complete audit trail and the ability to rebuild state at any point in time. CQRS (Command Query Responsibility Segregation) separates read and write models so each can be optimized independently.

Both patterns add significant complexity. Event Sourcing without a clear need creates an append-only log that is hard to query. CQRS without read/write contention creates two models to maintain for no benefit. This article explains when each pattern earns its complexity and how they work together in production systems.

Event SourcingStore events, not stateRebuild state from logAudit trail built inCQRSSeparate read/write modelsOptimize each sideOften paired with events
Event Sourcing vs CQRS

Event Sourcing

In traditional CRUD, updating an order status overwrites the previous value — history is lost. Event Sourcing appends events to an immutable log: OrderCreated, ItemAdded, PaymentReceived, OrderShipped. Current state is computed by replaying events — never stored directly. This gives you a complete audit trail, time-travel debugging ("what was the state at 3pm yesterday?"), and the ability to create new projections from historical events.

Event stores (EventStoreDB, Apache Kafka as event log, Marten for .NET) append events with versioning for optimistic concurrency. Snapshots optimize replay — store the computed state every N events so you do not replay thousands of events on every read. Event Sourcing works best for domains with complex lifecycles: orders, bank accounts, insurance claims, and inventory.

OrderCreatedItemAddedOrderPaidStateReplay events → current state. Never update, only append.
Event store: append-only log of domain events

Quick reference

  • Best for: audit requirements, complex domain lifecycles, temporal queries, event-driven systems.
  • Strengths: complete audit trail, time travel, new projections from old events, natural event-driven integration.
  • Weaknesses: query complexity, eventual consistency, learning curve, snapshot management.
  • Events are immutable — never update or delete, only append compensating events.
  • Use snapshots every 100-1000 events to avoid replaying entire history.
  • Event schema evolution: add new fields as optional, never remove or rename.

Remember this

Event Sourcing gives you perfect audit history — use it when the event log itself has business value.

CQRS

CQRS splits a single data model into two: a write model optimized for commands (create order, update inventory) and a read model optimized for queries (order dashboard, product catalog). The write model enforces business rules and emits events; the read model listens to events and builds denormalized views for fast queries.

This separation lets you scale reads and writes independently — 100 read replicas for the query side, one write node for commands. Different read models serve different screens: a summary view for the dashboard, a detailed view for the admin panel, a search index for full-text lookup. The trade-off is eventual consistency — after a command, the read model may lag by milliseconds to seconds.

Command\n(write)Write DB\n(normalized)EventsRead DB\n(denormalized)Query\n(read)
CQRS: commands write, queries read from optimized stores

Quick reference

  • Best for: read-heavy apps, complex queries, different views of same data, independent scaling.
  • Strengths: optimized read and write paths, independent scaling, multiple read models.
  • Weaknesses: eventual consistency, two models to maintain, complexity for simple CRUD.
  • Write side: validate commands, enforce invariants, emit domain events.
  • Read side: listen to events, build denormalized views, serve queries.
  • Do not use CQRS for simple CRUD — the overhead is not justified.

Remember this

CQRS separates reads from writes — use it when query patterns differ significantly from write patterns.

Using Event Sourcing and CQRS Together

Event Sourcing and CQRS complement each other naturally. The event store is the write model — commands append events. Read models are projections built by consuming those events. When an OrderPlaced event is appended, the order summary projection updates, the inventory projection decrements stock, and the notification projection sends an email.

This combination powers systems at scale: banking ledgers, e-commerce order management, and logistics tracking. The event log is the source of truth; read models are disposable — delete and rebuild from events if corrupted. Start with CQRS alone if reads and writes have different scaling needs. Add Event Sourcing when you need audit trails or temporal queries.

Quick reference

  • Event store = write model. Projections = read models. Events connect them.
  • Rebuild read models: replay all events from the beginning — disaster recovery built in.
  • Frameworks: EventStoreDB, Axon Framework (Java), Marten ( .NET), Eventuate.
  • Start simple: CRUD → CQRS (if read/write diverge) → Event Sourcing (if audit needed).
  • Projections can lag — design UI for eventual consistency (optimistic updates, polling).
  • Test projection rebuilds regularly — they are your disaster recovery mechanism.

Remember this

Combine them when you need both audit history and optimized reads — the event log feeds multiple read projections.

When NOT to Use These Patterns

Most applications do not need Event Sourcing or CQRS. A standard CRUD app with PostgreSQL handles 95% of business software. Adding event sourcing to a blog platform or task manager creates complexity with no benefit. Adding CQRS when you have one simple query per entity creates two codepaths to maintain.

Red flags that you might need these patterns: regulatory audit requirements, complex domain with many state transitions, read and write loads differ by 100x, or multiple consumers need different views of the same data. If none apply, stick with CRUD and a well-designed relational schema.

Quick reference

  • Skip Event Sourcing if: no audit requirement, simple state, team lacks DDD experience.
  • Skip CQRS if: reads and writes have similar patterns, small scale, simple queries.
  • CRUD + PostgreSQL handles most business apps — do not over-engineer.
  • Migration path: start CRUD, extract CQRS for hot read paths, add events when audit is required.
  • Complexity budget: every pattern must earn its place with a concrete requirement.
  • Interview tip: mention these patterns, explain trade-offs, but default to simpler solutions.

Remember this

Default to CRUD — adopt Event Sourcing and CQRS only when specific requirements justify the complexity.

Key takeaway

Share:

Event Sourcing and CQRS are powerful patterns for complex domains with audit requirements and divergent read/write needs. They are not defaults — they are responses to specific problems. Understand them for system design interviews and architecture discussions, but reach for CRUD first. When the domain demands it, the event log becomes your most valuable asset: immutable, replayable, and the single source of truth.

Related Articles

Synchronous microservices create invisible chains: when the payment service is slow, the order service is slow, and when

Read

Most .NET projects start clean and become entangled within six months. Controllers call repositories that call other ser

Read

Every new project faces the same question: one big application or many small services? The answer is rarely binary. A mo

Read

Keep learning

Follow a structured path or browse all courses to go deeper.