Event Sourcing

Most applications store state and discard how it got there. An accounts table says the balance is 240.00, and nobody can say which deposits and withdrawals produced that number. Event sourcing turns the storage inside out: the events are the source of truth, and the balance is a result computed from them, as many times as anyone needs.

offsetevent_typeaccount_idamountevent_timebalance after
10account_openedacc_770.002026-03-01 09:000.00
11depositedacc_77100.002026-03-02 10:15100.00
12depositedacc_77200.002026-03-10 16:40300.00
13withdrawnacc_7760.002026-03-15 12:05240.00

The last column is computed, never stored: start at 0 and apply each event in order, adding on deposited and subtracting on withdrawn. Any state that can be described as a start value plus a sequence of changes can be rebuilt this way, which covers account balances, inventory levels, order status, and a document's edit history.

Rebuilding state with a query

SELECT
  account_id,
  sum(
    CASE
      WHEN event_type = 'deposited' THEN amount
      WHEN event_type = 'withdrawn' THEN -amount
      ELSE 0
    END
  ) AS balance
FROM account_events
WHERE event_time <= TIMESTAMP '2026-03-31 23:59:59'
GROUP BY account_id

The WHERE clause is the part a state-based table cannot offer. Change the timestamp to March 12 and the same query returns 300.00, the balance as it stood that day, with no history table and no archived copy. Audits ask that question constantly. The second gift is repair: if the code that computes balances had a bug that subtracted each withdrawal twice for 3 weeks, the events are still right, because they record what was requested. Fix the code, run the fold again, and every balance is correct without a single hand-written correction.

Dashboards do not run this fold on every page load. A pipeline runs it on a schedule and writes the result to a plain account_balances table, called a read model. A read model is derived, so it can be dropped and rebuilt whenever the code or the question changes.

Snapshots

Replaying an account's 9 years of events to answer each balance request is slow, and a busy account can hold millions. A snapshot stores the computed state at a known offset. To get the current balance, read the snapshot, then apply only the events after its offset. The snapshot is a cache: delete it and the events rebuild it. Most systems take a snapshot every N events or every night, and keep the latest 1 or 2.

Current balance: 300.00 from the snapshot, minus 60.00 from offset 13, with no replay of offsets 10 to 12.

What event sourcing costs

For 3 weeks a bug in the withdrawal service wrote withdrawn events with the amount doubled. Balances computed from the log are now wrong. What is the correct repair?

About this lesson

This section is part of the Event Streams lesson on DataDriven, the home of data engineering. Lessons cover SQL, Python, Spark, data modeling and pipeline architecture, and each section pairs its explanation with worked examples and practice you run as you go.