Event Sourcing: When History Matters More Than State
I deleted a user's order. Not intentionally. A bug in our payment processing system overwrote the order state. The customer called, furious. "Where's my o...
1 Feb 2026

I deleted a user's order. Not intentionally. A bug in our payment processing system overwrote the order state. The customer called, furious. "Where's my order?" I had no idea. The database showed nothing. The logs showed nothing useful. We lost the history.
That's when event sourcing clicked for me.
Most systems store current state. You update a row. The old value disappears. History is gone. Event sourcing flips this. Instead of storing what something is, you store what happened to it. Every change becomes an immutable event in an append-only log.
What Event Sourcing Actually Is
Event sourcing means storing all changes to application state as a sequence of events. Instead of updating a record, you append an event. The current state is computed by replaying events from the beginning.
Think about a bank account. Traditional approach: balance is 1000. Someone withdraws 200. You update balance to 800. The 1000 is gone. The 200 withdrawal is gone. You only know the current state.
Event sourcing: AccountCreated with initial balance 1000. WithdrawalRequested for 200. WithdrawalCompleted for 200. The current balance is 800, but you have the full history. You can see every transaction. You can rebuild state at any point in time.
This isn't just about audit trails. It's about building systems that don't lose information.
Why This Matters in Production
I've seen too many systems lose critical information. A payment gets processed twice. The database shows one payment. The logs are rotated. You can't prove what happened. You can't debug the issue. You can't fix it properly.
Event sourcing solves this by making history the source of truth. Events are immutable. Once written, they don't change. You can replay them to rebuild state. You can query them to understand what happened. You can use them to debug production issues.
At MADE.com, we used Event Store for messaging between services. But event sourcing goes deeper. It's not just about messaging. It's about how you model your domain.
The Append-Only Log
The core of event sourcing is the append-only log. Events are written sequentially. They're never updated. They're never deleted. They're just appended.
This sounds simple. It is. But it changes everything about how you think about data.
Traditional databases are optimized for updates. You read a row. You modify it. You write it back. The database handles concurrency. It handles transactions. It's built for mutable state.
Event stores are optimized for appends. You write events. You read events. You don't update them. You don't delete them. This makes them fast. This makes them reliable. This makes them simple.
But it also means you can't just query for current state. You need to build read models. You need to project events into views. This is where CQRS comes in.
Event Sourcing and CQRS
Command-Query Responsibility Segregation separates reads from writes. You write to one model. You read from another. They're optimized for different things.
With event sourcing, your write model is the event log. Commands create events. Events are appended. That's it. Simple. Fast. Reliable.
Your read models are projections. Events flow through handlers. Handlers update views. Views are optimized for queries. They're denormalized. They're fast. They can be rebuilt from events.
This separation is powerful. Your write model stays simple. Your read models can be complex. They can be optimized for different queries. They can be rebuilt when you need to change them.
But it's also more complex. You have two models to maintain. You have eventual consistency to deal with. You have projection failures to handle.
The Trade-Offs
Event sourcing isn't free. It comes with real costs.
Storage. You're storing every change. Not just current state. Everything. This can grow large. You need strategies for archiving. You need strategies for snapshots — periodic checkpoints so you don't replay millions of events every time.
Complexity. You need to build read models. You need to handle projection failures. You need to deal with eventual consistency. You need to version your events. This is significantly more moving parts than a CRUD application.
Learning curve. Your team needs to understand events, projections, and replay. This takes time. I've seen teams adopt event sourcing and struggle for months because they're still thinking in CRUD terms.
But the benefits are real. Complete history. Full auditability. The ability to rebuild state. The ability to query history. The ability to debug production issues that would be impossible with a traditional database.
The question isn't whether event sourcing is good or bad. It's whether the benefits outweigh the costs for your use case.
When Event Sourcing Makes Sense
Event sourcing shines when history matters. When you need to know what happened. When you need to debug issues. When you need audit trails. When you need to rebuild state.
Financial systems. Order processing. Inventory management. Systems where losing history is expensive. Systems where you need to prove what happened.
It also works well with event-driven architectures. Events flow between services. Services react to events. The event log becomes the integration point. Services can replay events. Services can build their own views.
But it's overkill for simple CRUD. If you just need to store and retrieve data, traditional databases work fine. If you don't need history, don't pay the cost.
Internal Versus External Events
There's an important distinction between internal and external events. Internal events are for your domain model. They represent things that happened in your system. OrderAllocated. PaymentProcessed. InventoryUpdated.
External events are for integration. They're published to other systems. They're part of your API. They need to be stable. They need to be versioned. They need to be documented.
Not all internal events become external events. Some events are just for your domain. Some events get upgraded and published. This distinction matters. It keeps your domain model clean. It keeps your integration layer stable.
Versioning Events
Events will change. Your domain will evolve. Your requirements will change. You'll need to add fields. You'll need to change semantics. You'll need to handle old events.
This is hard. You need versioning strategies. You need migration paths. You need to handle old events when replaying. You need to handle schema evolution.
Greg Young wrote an entire book on this: Versioning in an Event Sourced System. It's worth reading. Event versioning is one of those problems that seems simple until you try to solve it.
Building with Events
If you're going to use event sourcing, start small. Model one aggregate with events. See how it feels. See if it helps. See if the complexity is worth it.
Use an event store. Event Store. Kafka. Something built for this. Don't try to build it yourself. Don't try to use a regular database. Use the right tool.
Build read models. Project events into views. Optimize for queries. Rebuild when you need to change.
Handle failures. Projections can fail. Events can be out of order. You need idempotency. You need retry logic. You need monitoring.
Version your events. Plan for change. Design for evolution. Handle old events gracefully.
The Bottom Line
Event sourcing changes how you think about data. Instead of storing state, you store history. Instead of updating records, you append events. Instead of losing information, you preserve it.
This comes with costs. More storage. More complexity. More things to learn.
But it also comes with benefits. Complete history. Full auditability. The ability to rebuild state. The ability to debug issues that would otherwise be unsolvable.
If history matters in your system — if you need to know what happened, not just what is — event sourcing might be worth it. If you just need to store and retrieve data, traditional approaches work fine.
I learned this the hard way. By losing data. By not being able to debug issues. By not having the history I needed. Now I think about events differently. I think about what happened, not just what is.
Keep reading
- The Capacity Estimation Numbers Every Engineer Should Carry Into a System Design
- Notes From My First Cohort: System Design Is Trade-offs, Not Answers
- Write HLDs and ADRs in HTML or React, Not Markdown
- CRDTs: Conflict-Free Merging in Distributed Systems
- Race Conditions: What They Are and How to Handle Them
- SLO, SLA, SLI: What They Actually Mean and How to Use Them