Event Sourcing Explained: Storing What Happened Instead of Current State
Learn event sourcing — storing every state change as an immutable event, with real examples from banking, e-commerce, and event-driven architectures.
Event Sourcing
Event sourcing is a data storage pattern where every change to an application's state is captured as an immutable event in an append-only log, and the current state is derived by replaying the sequence of events from the beginning.
What It Really Means
Traditional databases store the current state. An account balance is $500. When a $100 withdrawal happens, the balance becomes $400. The fact that it was ever $500 is gone (unless you audit-log separately).
Event sourcing inverts this. Instead of storing the current balance, you store every event that affected the balance:
- AccountOpened: balance = $0
- MoneyDeposited: +$1000
- MoneyWithdrawn: -$300
- MoneyDeposited: +$200
- MoneyWithdrawn: -$100
- TransferSent: -$300
The current balance ($500) is computed by replaying all events. The event log is the source of truth, not the current state. This means you can reconstruct the state at any point in time, answer questions you did not anticipate, and build new read models from historical data.
Event sourcing was popularized by Martin Fowler and Greg Young. It is used in banking and financial systems (complete audit trail), e-commerce (order lifecycle), gaming (replay systems), and version control (Git is essentially event sourcing for code — each commit is an event).
How It Works in Practice
The Event Store
An event store is an append-only database optimized for:
- Writing events sequentially (high write throughput)
- Reading all events for a specific aggregate/entity (replay)
- Reading events in order (stream processing)
Popular event stores: EventStoreDB (purpose-built), Apache Kafka (often used as an event store), PostgreSQL with an append-only events table, Amazon DynamoDB with sort key as event sequence.
Aggregates and Event Streams
Events are grouped into streams, typically one per aggregate (domain entity):
- Stream:
account-12345 - Events:
AccountOpened → MoneyDeposited → MoneyWithdrawn → ...
To load an aggregate, you read all events from its stream and replay them to rebuild current state. This is called "rehydration."
Real-World: Banking System
A bank account as an event-sourced aggregate:
| Seq | Event | Data | Resulting Balance |
|---|---|---|---|
| 1 | AccountOpened | {holder: "Alice", type: "checking"} | $0 |
| 2 | MoneyDeposited | {amount: 5000, source: "wire"} | $5,000 |
| 3 | MoneyWithdrawn | {amount: 200, atm: "ATM-42"} | $4,800 |
| 4 | TransferSent | {amount: 1000, to: "account-67890"} | $3,800 |
| 5 | InterestApplied | {rate: 0.001, amount: 3.80} | $3,803.80 |
Regulators ask: "Show all transactions above $1000 for this account in Q3 2025." With event sourcing, you query the event log directly. With traditional state-based storage, you hope your audit log captured everything.
Real-World: E-Commerce Order Lifecycle
An order's event stream captures the complete lifecycle:
Customer service can see exactly what happened: "The customer added 3 items, removed 1, applied a discount code, then submitted. Payment was authorized at 2:15pm but fulfillment was delayed 4 hours because the warehouse was backlogged."
Implementation
Trade-offs
Advantages
- Complete audit trail: Every change is recorded — essential for financial and regulatory compliance
- Temporal queries: Reconstruct state at any point in time ("What was the balance on March 15?")
- Event replay: Build new read models by replaying historical events — no data migration needed
- Debugging: Reproduce bugs by replaying the exact sequence of events that caused them
- Decoupled integration: Other services subscribe to events and build their own views (CQRS)
Disadvantages
- Complexity: Event-sourced systems are harder to build, test, and debug than CRUD systems
- Event schema evolution: Changing event formats requires versioning and upcasting old events — a challenging problem
- Replay performance: Aggregates with millions of events are slow to rehydrate. Snapshots help but add complexity.
- Eventual consistency: Read models built from events are asynchronously updated, creating a consistency lag
- Storage growth: The event log grows indefinitely. While storage is cheap, querying and compaction become concerns.
Common Misconceptions
-
"Event sourcing is just an audit log" — An audit log is a secondary record. In event sourcing, the event log IS the primary data store. Current state is derived, not stored. This is a fundamental architectural difference.
-
"You must use Event Sourcing with CQRS" — They are complementary but independent. You can use event sourcing without CQRS (derive state from events in the same model), and you can use CQRS without event sourcing (sync read models from a traditional database).
-
"Events should be fine-grained like database operations" — Events should represent domain-meaningful actions:
OrderPlaced, notRowInsertedIntoOrdersTable. Domain events capture business intent, not technical operations. -
"You never delete events" — Events are immutable, but regulations like GDPR require the ability to erase personal data. Techniques include crypto-shredding (encrypting personal data with a key that can be deleted) and event rewriting with tombstones.
-
"Event sourcing is always better than state-based storage" — For simple CRUD applications, event sourcing adds enormous complexity with little benefit. Use it when you genuinely need the audit trail, temporal queries, or the ability to rebuild state from history.
How This Appears in Interviews
Event sourcing appears in both system design and architecture interviews:
- "Design a banking transaction system" — event sourcing is the natural choice. Walk through the event store, aggregate design, snapshot strategy, and how you handle compliance requirements. See our system design interview guide.
- "How would you add a new analytics feature to an existing system?" — with event sourcing, you replay historical events into a new read model. Without it, you need to backfill from existing data.
- "How do you handle event schema changes?" — discuss event versioning, upcasters that transform old events to the new schema, and weak vs strong schema enforcement.
- "What is the relationship between Event Sourcing and CQRS?" — explain that they are independent patterns often used together, and describe the benefits of the combination.
Related Concepts
- CQRS — Separating reads and writes, often combined with event sourcing
- Saga Pattern — Coordinating multi-step processes using events
- Eventual Consistency — Read models are eventually consistent with the event log
- Two-Phase Commit — The traditional alternative for cross-service consistency
- System Design Interview Guide — Framework for architecture discussions
- Algoroq Pricing — Practice event-driven architecture interview questions
GO DEEPER
Learn from senior engineers in our 12-week cohort
Our Advanced System Design cohort covers this and 11 other deep-dive topics with live sessions, assignments, and expert feedback.