Event Versioning¶
Events are immutable – but your understanding of the domain isn't.
Over time, your system will evolve. New requirements will emerge. And eventually, you'll need to change the structure of your events.
This raises an important question:
How do you deal with old events when your models have changed?
Why Versioning Matters¶
Event stores keep every event ever emitted. That includes outdated formats, old field names, and past assumptions.
If your system expects a new structure, replaying those old events can lead to errors – or worse, incorrect behavior.
That's why event versioning is essential.
Three Common Approaches¶
There's no one-size-fits-all strategy – but here are the most common ones.
Upcasting on Read¶
Update events as they are read, converting them from their old format to the current one.
- Keeps stored data untouched
- All versioning logic is centralized in one place
- Can become complex over time if many versions exist
Event Transformation¶
Rewrite events in the store (or in a shadow store) to match the new format.
- Makes event handling easier downstream
- Loses original format – which may be important for auditing
- Requires careful coordination and backup
Polymorphic Handlers¶
Allow multiple versions of an event to coexist, and handle them accordingly.
- Each handler supports its version
- No rewriting or transformation needed
- Can clutter logic over time
Best Practices¶
- Use version numbers or schema identifiers in your events
- Keep versioning logic isolated from core domain logic
- Document why each version exists and how it differs
- Consider the impact on snapshots, projections, and analytics
Summary¶
Change is inevitable – and your event history needs to keep up.
With careful versioning, you can evolve your system without losing the benefits of immutability and auditability.
Next up: Find out why accessing read models from the write side is tempting – and why it's usually a bad idea – in Accessing Read Models from the Write Side.