Skip to main content

Concepts

Double-entry ledger

Intuition

Think of a network of pipes that carries water from a faucet to reservoirs: everything that leaves one point has to arrive at another, and the pipes in the middle, when the flow ends and everything worked, are left empty. If water is left standing in a pipe, you know something along the way went wrong, and you know exactly where to look. A double-entry ledger does the same with money: every amount that leaves one place enters another, and nothing is erased from the book, new lines are only added.

How it works

In double-entry bookkeeping, every movement is recorded as a debit in one account and a credit in another, so that credits and debits balance and all the money in the system is accounted for. In Stripe's Ledger, each producer system is modeled as a logical flow of funds: accounts are buckets of money distinguished by type and properties (such as id and business), and events move balance between them. A charge, for example, has a creation event, which puts value into an account of funds not yet disbursed, and a release event, which moves it to the company's balance; the two are independent and the Ledger joins them by their identifiers, even if they arrive out of order or from different sources. The core is an immutable log of events: published transactions cannot be deleted or altered, and past state can be reconstructed by processing the events up to that point, because balances and flows are transformations of this static structure. In steady state, when the flows have already completed, the clearing (intermediate) accounts sit at zero; a release that never arrives, or that arrives with the wrong id or business, leaves a nonzero balance in them, and a simple query for clearing accounts with a nonzero balance when they should already be zero reveals the problem. Since you do not fix data with an UPDATE, the correction is to revert and reprocess earlier operations, with migrations protected by review and two-phase commit and by data quality reports outside the execution flow.

In practice

This design appears in financial systems that need to prove to internal customers and external auditors that money moved as expected, even with independent services, different delivery rhythms and imperfect data. In reconciliation, each account's balance is derived from the event history and, when the flow should already have completed, a non-zero residue in a clearing account points to a missing, late or incorrect event and shows in which account it ended up. The post reports more than 99.9999% explainability of money movement; the cost is that corrections require reversal and reprocessing instead of direct editing, and the post does not discuss idempotency or the handling of duplicate writes.

Use it in a design

Practice the cases that rely on this concept in the System Design school.