SaaS technology
Businesses SaaS July 19, 2026 • 8 min read

What Is Event Sourcing? Stop Losing the Why Behind Your Data

For: A COO or product lead at a 50–200-person B2B SaaS company who keeps getting burned by support tickets they cannot answer — a customer's account is in a broken state, no one can reconstruct how it got there, and the engineering team says the database only stores what is true now, not what happened

Event sourcing is a way of storing data where you save every change as an immutable event, and derive the current state by replaying those events in order. Instead of a customer record that says balance: $412, you have a log that says deposited $500, withdrew $88, applied $0 fee — and $412 is just what you get when you add them up. This matters because when something breaks, you can replay history to see exactly how the account got into a bad state. Your database stops throwing away the why.

If you run a SaaS product and your support team keeps escalating tickets that engineering cannot answer — “the invoice total is wrong,” “the account is stuck in this weird status,” “the customer swears they never enabled this” — you are paying the price of a data model that only remembers the present. Event sourcing is one of the cleaner ways out.

The problem: your database is a whiteboard, not a ledger

Most SaaS applications use CRUD on top of a relational database. Create, Read, Update, Delete. When a user changes their subscription tier from Pro to Enterprise, the users table gets an UPDATE statement. The old value is gone. Unless someone had the foresight to write it to an audit table — and unless every code path that touches that record does the same — the change is invisible an hour later.

This works fine until it doesn’t. Then a customer calls and says their seat count is wrong, or their billing cycle shifted, or a feature flag flipped. You open the record. It says what it says. There is no way to know how it got that way, who changed it, when, or in what order relative to other changes. Every post-mortem devolves into stitching together application logs, Stripe webhooks, and Slack messages. Sometimes you find the answer. Often you don’t.

The instinct is to bolt on an audit log. Add a trigger. Log every write. This helps, but it is a patch on a leaky abstraction — one migration, one bulk update, one direct SQL fix from an engineer at 2am, and the audit trail has a hole in it. The problem is not that you forgot to log. The problem is that logging is optional.

The insight: invert the model

Event sourcing does not add history to your data. It makes history be your data.

The events are the source of truth. Current state is a projection — a cached summary you compute by replaying events. You cannot “forget” to log a change because there is no other way to change anything. The only write operation your system supports is append event. There is no UPDATE. There is no DELETE. Correcting a mistake means appending a compensating event, not overwriting the past.

This is the difference between a whiteboard and a bank ledger. A whiteboard shows what someone last wrote. A ledger shows every transaction, and the balance is derived. You cannot tamper with row 47 of a ledger without it being obvious that row 47 changed.

An analogy: your bank statement

Your checking account balance is $2,431.19. That number is not stored anywhere authoritative. It is the sum of every deposit, withdrawal, transfer, and fee since the account opened. If the bank’s system showed you $2,431.19 but could not tell you how it got there, you would close the account. Yet this is exactly how most SaaS databases work.

Event sourcing is your product built like the bank statement, not like the balance printout.

A minimal worked example

Say you sell a B2B SaaS product with team accounts. A customer complains: “We are being billed for 12 seats but we only have 8 users.”

In a CRUD system, you look at the accounts table. seat_count: 12. You have no idea why.

In an event-sourced system, you query the event stream for account acme-corp:

2024-01-03  AccountCreated            seats=5   actor=signup
2024-02-11  SeatsAdded                +3        actor=admin@acme.com
2024-04-22  UserInvited               user=jane@acme.com
2024-04-22  SeatsAdded                +1        actor=system (auto-provision)
2024-06-01  UserRemoved               user=bob@acme.com
2024-06-01  (no seat change)
2024-07-15  SeatsAdded                +3        actor=admin@acme.com
2024-08-02  UserRemoved               user=carol@acme.com

Now the story is obvious. Auto-provisioning added a seat when Jane was invited, but removing Bob and Carol did not decrement seats. The admin also manually added 3 seats in July, probably planning for hiring that didn’t happen. The customer is not wrong. Neither is the billing system. The policy is wrong — removals should have released seats.

You could not have reached this diagnosis from seat_count: 12. And crucially, no one had to remember to log any of this. It is how the system stores data.

How this shows up in architecture

Event sourcing usually travels with a few companion patterns. You do not have to adopt all of them, but you will hear the names.

The gotchas — what event sourcing is bad at

This is not a free upgrade. Real tradeoffs:

When to use event sourcing vs when not to

Use it when:

Do not use it when:

A middle path worth considering: keep CRUD for most of your app, and event-source only the subsystems where history is non-negotiable — billing, entitlements, compliance-sensitive workflows. This is often what pragmatic teams end up with after they read the textbook and meet reality. Getting that boundary right is usually the harder half of a legacy modernization effort than the code itself.

The bottom line on event sourcing vs CRUD

CRUD stores what is true. Event sourcing stores what happened, and derives what is true. If your business runs on the second question more than the first — if support tickets keep asking “how did this account end up like this” and you keep not having an answer — you have outgrown CRUD in the places that matter. You do not need to rewrite everything. You need to identify the two or three aggregates where history is the product, and model those as events.

Frequently Asked Questions

Is event sourcing the same as having an audit log?

No. An audit log sits alongside your normal data and can be forgotten, bypassed, or corrupted by a bulk migration. Event sourcing makes the events themselves the primary data — there is no other way to change state, so the history cannot be turned off or skipped.

Do we have to rewrite our entire application to adopt event sourcing?

Almost never worth doing. Most teams event-source only the subsystems where history matters — billing, entitlements, order workflows, compliance — and leave the rest as CRUD. The boundary between the two is the important design decision.

How does event sourcing relate to Kafka or event-driven architecture?

Kafka and similar log-based brokers are one way to implement the event store, and event-driven architecture is what naturally emerges once events are first-class. But event sourcing is a data modeling choice, not a specific tool. You can event-source with a Postgres table if the volume is modest.

What about GDPR if events are immutable?

You handle it with techniques like crypto-shredding (encrypt personal data with a per-user key and delete the key), keeping PII out of event payloads and in a separate deletable store, or issuing tombstone events. It requires planning but is a solved problem in regulated industries.

How do we know if event sourcing is right for our product?

Look at your support tickets from the last quarter. Count how many required someone to reconstruct history that the database did not store. If that number is meaningful and growing, at least part of your system should be event-sourced. For a scoped assessment of where the boundary should sit, talk to CodeNicely for a personalized review.

Found this useful? CodeNicely publishes engineering and product playbooks weekly. Browse the archive or tell us what you're building.