DEV Community

Navidreza Abbaszadeh
Navidreza Abbaszadeh

Posted on

Event Sourcing & CQRS Explained

As applications grow, the traditional request/response (req/res) model starts showing cracks.

With two services (A -> B), things are simple: one service calls the other and gets a response.

But as soon as more services (C, D, …) join in, the complexity explodes. Instead of just a couple of connections, you now face a web of dependencies where every service potentially talks to every other service.

This is where event-driven architecture (EDA) patterns like Event Sourcing and CQRS come to the rescue.

What’s an Event?

An event is just a signal that something significant has happened.

Example:

OrderPlaced -> when a customer creates a new order

StockDecreased -> when inventory updates after the order

Main Components of EDA:

Producers: Services that generate events (e.g., OrderService)

Consumers: Services that react to events (e.g., InventoryService)

What is Event Sourcing?

Normally, systems just store the latest state of data.

But with Event Sourcing, instead of saving only the current state, we store all the events that happened to reach that state.

Think of it as a ledger of every change.

Example: Bank Account

AccountOpened (Initial Balance: $0)

DepositMade (Amount: $350)

WithdrawalMade (Amount: $300)

Current State -> Balance: $50

Instead of just storing “Balance = $50,” we store the entire history of events.

Benefits

Audit Trail: Full history of changes is always available.
Rebuild State Anytime: You can replay events to rebuild the current state.

Problem

Replaying every single event from the beginning can be slow and inefficient.

How Do We Solve This?

  1. Hydration & Replay

Hydration: Rebuilding the current state by applying all events in order.

Replay: Reprocessing the entire event stream (or large parts of it) to recompute the current state.

  1. Snapshots (Sourcing Optimization)

Instead of replaying every event since the beginning of time:

Periodically capture the current state as a snapshot (e.g., every 100 events).

To rebuild, load the latest snapshot and apply only the events that happened afterward.

This dramatically improves performance.

  1. Materialized Views

For read-heavy systems, we often maintain pre-computed, query-optimized views of the current state in a separate database.

Think of it like a cached read model.

Producers keep emitting events, and consumers build these views in real-time.

CQRS (Command Query Responsibility Segregation)

Traditional systems use the same model for:

Commands (writes) -> change the system state

Queries (reads) -> retrieve system state

CQRS separates these responsibilities:

Command Side: Handles writes, stores events.

Query Side: Builds materialized views optimized for reads.

This separation makes systems more scalable, maintainable, and flexible.

Putting It All Together

Events capture what happened.

Event Sourcing stores the full history, not just the current state.

Snapshots & Hydration make it efficient to rebuild state.

Materialized Views provide fast access to the current state.

CQRS separates the write model (commands & events) from the read model (queries & views).

Top comments (0)