Most databases only know one thing: what's true right now. Update a row, and whatever was there before is gone for good. The Event Sourcing pattern works differently -it doesn't store the current value at all, it stores every single change that ever led up to it. The "current state" is something you calculate on the fly, not something sitting in a column.
How Git Changed How We Think About State
Git does not store the current version of your code. It stores every commit - every change that ever happened. You can go back to any point in time. You can see who changed what and when. You can branch from any historical state. Event sourcing applies this exact principle to your database. Instead of storing 'Account balance: $500,' you store every deposit and withdrawal that led to $500.
Traditional vs Event-Sourced
Traditional (stores current state):
accounts table:
| id | balance | updated_at |
|-----|---------|---------------------|
| 42 | $500 | 2024-01-15 14:32:00 |
Q: How did we get to $500? A: No idea. It is just $500 now.
Q: Was there a $10,000 withdrawal yesterday? A: Cannot tell.
Event-Sourced (stores history of changes):
events table:
| aggregate_id | seq | event_type | data | timestamp |
|-------------|-----|-------------|---------------|---------------------|
| 42 | 1 | Created | {balance: 0} | 2024-01-01 09:00:00 |
| 42 | 2 | Deposited | {amount: 1000}| 2024-01-05 10:30:00 |
| 42 | 3 | Withdrew | {amount: 300} | 2024-01-08 14:15:00 |
| 42 | 4 | Deposited | {amount: 200} | 2024-01-12 09:45:00 |
| 42 | 5 | Withdrew | {amount: 400} | 2024-01-15 14:32:00 |
Current balance = 0 + 1000 - 300 + 200 - 400 = $500
Complete audit trail. Full history. Time travel.What You Get for Free
This is where the Event Sourcing pattern earns its keep-a handful of hard problems get solved automatically just because your data is shaped this way.
Event Sourcing Superpowers:
1. AUDIT LOG (free):
Every change is recorded with who, what, when.
Compliance teams love this. No separate audit system.
2. TIME TRAVEL:
'What was the account balance on Jan 8?'
Replay events 1-3: 0 + 1000 - 300 = $700
3. BUG ANALYSIS:
Production bug caused wrong balance?
Replay events locally to reproduce exact state.
4. REBUILD PROJECTIONS:
Want a new dashboard view? Create a new projector,
replay ALL events, get a fully-built read model.
Changed your data schema? Delete projection, rebuild.
5. WHAT-IF ANALYSIS:
'What if we had applied a 2% fee?'
Replay events with fee logic -> see impact.None of these needed a separate system built on the side. They just fall out of storing history instead of a single number.
Snapshots: Making It Fast
The Performance Problem:
Account with 10,000 events -> replay all on every read?
That is 10,000 operations just to get current balance.
Snapshot Solution:
Every 100 events, save a snapshot:
| aggregate_id | snapshot_seq | state |
|-------------|-------------|---------------------|
| 42 | 100 | {balance: $2,340} |
| 42 | 200 | {balance: $5,120} |
To get current state (at event 215):
1. Load snapshot at seq 200: balance = $5,120
2. Replay events 201-215 only (15 events)
3. Much faster than replaying all 215 eventsThe full history never goes anywhere-the snapshot is just a shortcut so reads don't have to crawl through it every time.
The Challenges (Be Honest About Them)
No write-up on Event Sourcing architecture is complete without admitting where it actually costs you something.
Challenge Problem Solution
----------------- ------------------------- ----------------------
Schema evolution Event v1 has different Upcasters: transform
fields than event v3 old events on read
Eventual consist. Projections lag behind Accept ~100ms lag or
the event store use read-your-writes
Query complexity 'Find all users in NYC' Build read projections
is impossible on events for every query pattern
Storage growth Events accumulate forever Archival policies,
compaction strategies
Mental model Teams think in state, Training, gradual
not in events adoptionThat mental model shift is honestly the hardest one on this list. Tooling can fix the rest; getting a team to stop thinking "the balance is $500" and start thinking "the balance is the sum of everything that happened to it" takes actual time.
Interview Tip
When discussing event sourcing in a design, say: 'For a domain where audit trail, time travel, and event replay are valuable - like banking, e-commerce orders, or inventory - I would use event sourcing. Instead of storing current state, I store an append-only log of domain events. Current state is derived by replaying events, with periodic snapshots for performance. For queries, I build read projections (CQRS) from the event stream. The trade-offs are eventual consistency on reads, schema evolution complexity for old events, and the mental shift from state-based to event-based thinking.'
<
Architecture overview
/blockquote>
Key Takeaway
Event sourcing stores history rather than current state. You get audit logs, time travel, and rebuildable projections for free. The trade-offs are schema evolution complexity and the need for snapshotting at scale. Pair it with CQRS for the full pattern.
Related reading
