Snapshots, Versioning, and Event Schema Evolution
Speed up rehydration with snapshots and evolve event schemas without breaking historical data.
Why Rehydration Gets Slow
In Event Sourcing, the current state of an aggregate is rebuilt by replaying every event from the start of its stream. This is called rehydration.
For a fresh bank account with 12 events, replaying them is instant. But a long-lived aggregate (an account open for 5 years, a shopping cart with thousands of edits) can accumulate tens of thousands of events. Loading and folding all of them on every command becomes the bottleneck.
- I/O cost: reading thousands of rows from the event store
- CPU cost: folding each event through the reducer
- Latency: every write must first rehydrate before validating the next command
The standard fix is a snapshot: a periodic, serialized copy of the aggregate state so you only replay events after it.
Rehydration as a Fold
Before optimizing, make rehydration explicit. An aggregate's state is a left fold over its events: state = events.reduce(apply, initialState).
Here is a minimal account aggregate. The apply function is a pure reducer — given the previous state and one event, it returns the next state. Notice it never mutates; it returns new objects so it stays easy to reason about and test.
function apply(state, event) {
switch (event.type) {
case 'AccountOpened':
return { ...state, balance: 0, version: state.version + 1 };
case 'MoneyDeposited':
return { ...state, balance: state.balance + event.amount, version: state.version + 1 };
case 'MoneyWithdrawn':
return { ...state, balance: state.balance - event.amount, version: state.version + 1 };
default:
return state;
}
}
function rehydrate(events) {
const initial = { balance: 0, version: 0 };
return events.reduce(apply, initial);
}
const events = [
{ type: 'AccountOpened' },
{ type: 'MoneyDeposited', amount: 100 },
{ type: 'MoneyWithdrawn', amount: 30 },
];
console.log(rehydrate(events)); // { balance: 70, version: 3 }All lessons in this course
- Events as the Source of Truth and the Append-Only Log
- Aggregates, Commands, and Domain Event Modeling
- Building Read Models and Projections
- Snapshots, Versioning, and Event Schema Evolution