beginner~2h

Introduction to Event Sourcing

Understand event sourcing: storing every change as a permanent event instead of just the latest state, and why this approach pairs so naturally with CQRS.

Learning objectives

  • Explain the difference between storing current state and storing a history of events.
  • Describe how current state gets rebuilt by replaying a stream of events.
  • Explain why event sourcing is usually paired with CQRS rather than used on its own.
  • Recognize that event sourcing and CQRS are separate, independently adoptable patterns.

◆ Story

A bank account has a balance: one single number, right now. But a bank also keeps a statement: a complete, ordered list of every deposit and withdrawal that ever happened to that account, going back to the day it was opened. The balance is derived from the statement — it's simply the result of adding up every entry, in order. If a bank somehow lost the balance number but still had the statement, it could recalculate the exact balance perfectly, just by re-adding everything from the beginning. If it lost the statement but kept only the balance, it would have a number with zero explanation for how it got there.

Event sourcing takes this idea and makes it the foundation for how a system stores everything, not just bank balances. Instead of storing "the current state" directly, a system stores every single change as an event, and current state becomes something calculated by replaying those events — exactly like recalculating a balance from a statement.

This reframes a familiar question. Instead of asking "what is this customer's current address," an event-sourced system asks "what is the full sequence of things that happened to this customer, and what does replaying all of them tell us right now?" The answer to the second question always includes the answer to the first, plus everything else.

Traditional approach (storing state)Event sourcing (storing events)
What's savedThe current row: {name: "John Smith", email: "john@email.com"}Every change: CustomerCreated, then CustomerNameUpdated, then CustomerEmailUpdated
HistoryGone the moment a new value overwrites the old onePermanently preserved — exactly what changed, when, and with enough context, why
"What did this look like last Tuesday?"Impossible to answer unless separate audit logging was builtSimply replay events only up to last Tuesday

The traditional approach optimizes for a very specific, very common question: "what is true right now?" It answers that question extremely efficiently, with one row lookup. But it actively discards the information needed to answer almost any other interesting question about how that row got the way it is.

Event sourcing makes the opposite trade. It's slightly more work to answer "what is true right now," because that answer has to be computed rather than read directly — but it preserves everything needed to answer nearly any question about history, change, and cause, for free, because none of that information was ever thrown away in the first place.

For a bank, this distinction isn't academic. Regulators frequently require a full, provable history of every change to a customer's account or credit profile — not just its current value. A traditional system has to bolt on separate audit logging to satisfy that requirement; an event-sourced system gets it as a natural side effect of how it already stores data.

Consider a single customer's event history, in order: first a CustomerCreated event, then a NameUpdated event changing the name to "John Smith," then an EmailUpdated event changing the email to a new address. None of these events, on their own, is "the current state" — each one is just a fact about one specific change that happened at one specific moment.

To find out what's true about this customer right now, an event-sourced system replays every one of these events, in order, applying each one's effect on top of the last. CustomerCreated establishes that the customer exists. NameUpdated overwrites the name field with "John Smith." EmailUpdated overwrites the email field with the new address. After replaying all three, the resulting state is exactly what a traditional system would have stored directly in a row — the difference is that this state was calculated, not stored as the primary record.

◆ Under the hood

This is the single biggest mental shift event sourcing asks for. In a traditional system, events — if they're logged at all — are usually an afterthought, a side effect of the "real" update to a row. In event sourcing, it's reversed: the events are the real, permanent record. Current state is just a convenient, disposable calculation, one that could be deleted and perfectly recalculated at any time, as long as the underlying events themselves are kept safe.

In practice, nobody wants to replay thousands of events every single time a piece of current state is needed, so real systems typically cache the calculated result and only replay events since the last cached point — but the underlying principle stays the same: the events are the truth, and current state is just a snapshot of what they add up to.

Event sourcing, on its own, is genuinely bad at answering questions like "show me this customer's profile" — potentially hundreds of events would need replaying just to answer one simple read. This is exactly why event sourcing and CQRS are so often used together: the write side stores events for a perfect, permanent history, while a separate query side maintains a fast, ready-to-read copy built by listening to those same events as they happen. Each side gets to do the job it's actually good at, instead of one model being forced to do both.

▲ Common mistake

Assuming event sourcing and CQRS are the same thing, or that adopting one requires adopting the other. They solve different problems and are genuinely separable: a system can do CQRS with traditional state storage on its write side, with no events involved at all, and a system can do event sourcing without a separately optimized read side — though that's rarely a good idea, for exactly the reason described above, since every read would have to replay events from scratch. Many real-world event-sourcing frameworks and toolkits support command/query separation directly, which is part of why the two patterns end up paired together as often as they do — not because they're the same idea, but because they solve complementary halves of the same larger problem.

A useful way to remember the split: event sourcing is a decision about how the write side stores its history; CQRS is a decision about whether reads and writes get separate models at all. They tend to travel together in practice, but neither one requires the other.

Banking and financial systems are some of the most natural real-world fits for event sourcing, precisely because regulators and auditors already expect a complete, provable history of every change — event sourcing provides that as a structural property of the system rather than as bolted-on logging. A ledger of every deposit, withdrawal, and transfer is, in a very real sense, already an event-sourced design, whether or not the team building it uses that specific term.

Version control systems are a familiar everyday example of the same underlying idea: a codebase's current state is never stored as the "real" record — it's the result of replaying every commit, in order, from the very first one. Nobody stores "the current file contents" as the source of truth; they store the sequence of changes and derive current contents from it, exactly like an event-sourced customer record.

E-commerce order systems, inventory systems that need to explain exactly why stock levels changed, and collaborative applications that need conflict resolution or "undo" functionality are other common adopters — anywhere that being able to answer "how did we get here, exactly" is a real, recurring business need rather than a nice-to-have.

Q: In event sourcing, is "current state" something stored directly, or something calculated? A: Calculated — it's the result of replaying every past event for that object, in order; nothing about it is stored directly as the source of truth.

Q: What question does event sourcing answer that a traditional "store the latest state" approach cannot answer without extra work? A: "What did this look like at an earlier point in time" — event sourcing answers it by simply replaying events only up to that point.

Q: Why is event sourcing usually paired with CQRS rather than used alone? A: Because replaying potentially hundreds of events to answer every simple read would be slow; CQRS's separate, fast read side, kept in sync by listening to the same events, solves exactly that gap.

Q: Are event sourcing and CQRS the same pattern? A: No — they're separate, independently adoptable patterns that happen to pair well together; a system can use CQRS without events, or event sourcing without a separately optimized read side.

Want a visual for this concept?

Generate a diagram tailored to “Introduction to Event Sourcing” — the AI picks whichever visual (flowchart, comparison, sequence, etc.) best fits.

Sign in to generate a visual →

Practice quiz

Next Step

Continue to Meet Axon Framework & Axon Server← Back to all Event-Driven Microservices chapters