Skip to content

What is Event Sourcing

Key idea:

Event Sourcing — pattern where current state is derived from a sequence of immutable events stored in an event log. Instead of UPDATE user SET balance = 100, write BalanceCredited {amount: 100}. Benefits: full audit trail, time-travel queries, state rebuild. Costs: tricky schema migrations, eventual consistency, "upcasting" old events as schemas evolve.

Below: details, example, related terms, FAQ.

Check your site →

Details

  • Append-only log: events immutable, order matters
  • Event store: EventStore DB, Kafka, Postgres tables
  • Snapshots: for performance — periodic state dump
  • Projections: read models built from event stream
  • Upcasters: transform old event versions into new

Example

// Events append
EventStore.append('order-123', [
  OrderCreated { customerId, items }
  OrderConfirmed { timestamp }
  OrderShipped { trackingNumber }
])
// Rebuild state by replaying events
state = fold(events, initialState, applyEvent)

Related Terms

Understanding Event Sourcing in Depth

Event Sourcing is a design pattern that revolves around the idea of persisting the state of a system as a series of events. Each event represents a state change, and rather than storing the current state directly, you store a log of these events. This approach offers several advantages:

  • Audit Trail: Every change is recorded, allowing for a complete history of actions taken on the system.
  • Rebuilding State: The current state can be reconstructed by replaying the event log, providing flexibility in state management.
  • Time-Travel Queries: You can query the state of the system at any point in time by replaying events up to that specific moment.

However, Event Sourcing also introduces complexities, such as managing schema evolution and ensuring eventual consistency. It is essential to understand these aspects to effectively implement Event Sourcing in your applications.

Practical Examples of Event Sourcing Implementation

Implementing Event Sourcing requires a clear understanding of how to capture and store events. Below is a practical example illustrating how to use Event Sourcing in a simple banking application:

class Account {
private List events = new ArrayList<>();

public void credit(int amount) {
events.add(new BalanceCredited(amount));
}

public void debit(int amount) {
events.add(new BalanceDebited(amount));
}

public int getBalance() {
int balance = 0;
for (Event event : events) {
if (event instanceof BalanceCredited) {
balance += ((BalanceCredited) event).amount;
} else if (event instanceof BalanceDebited) {
balance -= ((BalanceDebited) event).amount;
}
}
return balance;
}
}

In this example, the Account class maintains a list of events and uses them to compute the current balance. Each time a credit or debit occurs, an event is created and added to the log. This allows you to reconstruct the account's state at any point by iterating through the events.

Common Challenges in Event Sourcing

While Event Sourcing provides significant benefits, it also comes with its share of challenges that developers must navigate:

  • Schema Migrations: As the application evolves, the structure of events may need to change. This can complicate how events are stored and processed. Developers often need to implement strategies for migrating old events to fit new schemas.
  • Eventual Consistency: In distributed systems, achieving immediate consistency can be difficult. Event Sourcing typically leads to eventual consistency, where the system may not reflect the latest state immediately after an event is processed.
  • Upcasting: As event schemas change, older events may need to be transformed (or upcast) to match the current schema when they are replayed. This adds an additional layer of complexity to the design.

Addressing these challenges requires careful planning and a robust architecture to ensure that the advantages of Event Sourcing are realized without compromising system integrity.

Learn more

Frequently Asked Questions

Is Event Sourcing only for CQRS?

No, but often combined. ES gives write-side, CQRS separates read and write models.

How to deal with schema changes?

Upcasters: at read time, transform old event versions to new schema. Or versioned event types (OrderCreated_V1, V2).

Storage size — a problem?

Events grow linearly. For long-lived streams — snapshots every N events. Or archive old events to cold storage.

Try the live tool that powered this guide

Free plan — 10 monitors, checks every 5 min, no card required. Upgrade for 1-minute interval and multi-region monitoring.