Journal

How to Scale a Ledger, Part III: Transaction Models

In the third part of this series, we'll look at how Transaction models enable atomic money movement and enforce double-entry.

Image of Matt McNierney
Matt McNierneyEngineering

Updated on August 22, 2025.

This post is the third chapter of a broader technical paper, How to Scale a Ledger. In Part I, we covered why you should use a ledger database, and in Part II, we mapped common financial events to double entry primitives like Accounts and Entries. In this chapter, we look at a transaction model to enable atomic movement.

Why Transactions Matter in Ledger Systems

While Accounts and Entries within ledger databases provide an immutable audit trails of balance changes, they aren’t enough on their own. Without a Transaction object, it’s possible to create inconsistent states if only part of a money movement is recorded.

A well designed transaction model provides:

  • Atomicity: All Entries must succeed or fail together
  • Consistency: Prevents partial state changes
  • Double-entry enforcement: Ensures balanced Entries for every transaction
Transaction
Transaction fields and descriptions

Transaction Schema: Digital Wallet Transfer Example

Consider a simple transfer of money between accounts in a peer-to-peer wallet app. Let’s say Bobby sends Alice $10; we can represent that transfer as two Entries: bobby_entry and alice_entry.

Two Digital Wallet Entries
Two entries representing a $10 digital wallet transfer from Bobby to Alice

Imagine that bobby_entry was successfully written, but the corresponding alice_entry failed to write (maybe the database was having network issues). Now the ledger is in an inconsistent state—Bobby was debited money, but Alice didn’t get anything. Money is lost.

Transactions solve this consistency problem by allowing us to specify groups of Entries that either must all succeed or all fail. In order to guarantee atomicity, all the non-discarded Entries on a Transaction must share the status of the Transaction. This ensures that all Entries progress in status at the same time, all-or-nothing.

A Ledger API should only allow clients to directly create Transactions, not Entries. This limitation helps ensure clients don’t run into consistency problems. However, that means a Ledger API must manage creating Entries itself. There are three operations to implement, corresponding to the possible states of the Transaction:

  1. Pending (initial state)
  2. Posted (finalized)
  3. Archived (canceled before posting)

Creating a Pending Transaction

This is generally the first step in the lifecycle of a Transaction. The system persists the debit and credit Entries as pending, but the transaction is not finalized.

Persisting the two entries
Persisting the $10 digital wallet transfer from Bob to Alice to create a Transaction

Posting a Transaction (Finalizing It)

Since Entries are immutable, when we move a Transaction from pending to posted, we need to:

1. Discard the pending Entries (bobby_entry_1 and alice_entry_1).

Discard entry_1
Discarding pending entries bobby_entry_1 and alice_entry_1

2. Create new posted Entries. This preserves immutability: posted Entries are never modified.

Create posted entries
Now posted, the $10 transaction is immutable

Archiving a Transaction (Canceling It)

Posted Transactions are immutable, and so cannot be archived. So what if the transaction was canceled?

Pending Transactions can have their status changed to archived, following a similar process to posting.

1. Discard pending bobby_entry_1 and alice_entry_1.

Discard pending transactions to be archived
Discarding pending transactions bob_entry_1 and alice_entry_1 to be archived

2. Create new Entries with archived status.

Create archived entries
Archived entries show the $10 transaction was canceled, but retains the history

Next Steps

This is the third chapter of a broader technical paper with a more comprehensive overview of the importance of solid ledgering and the amount of investment it takes to get right.

If you want to learn more, download the paper, or get in touch.

Read the rest of the series:

Part I | Part II | Part IV | Part V | Part VI

Authors
Image of Matt McNierney
Matt McNierneyEngineering

Matt McNierney serves as Engineering Manager for the Ledgers product at Modern Treasury, leading the design and execution of high-performance, double‑entry financial infrastructure. Under his technical stewardship, Ledgers has become the backbone for fintech platforms that demand both precision and scale.

With a deep commitment to performance and correctness, Matt’s team engineered a ledger system capable of sustaining 1,200 ledger transactions per second alongside 3,600 concurrent balance reads, while maintaining sub‑second latency for both writes and reads—even under peak pressure.

A frequent contributor to Modern Treasury’s technical community, Matt has shared his expertise in forums like “How We Built Ledgers for High Throughput” and the “Building a Central Ledger” tech talk. In these sessions, he unpacks engineering challenges such as concurrency controls, granular account design, and how to ensure data consistency in distributed financial systems.

Matt holds a B.A. in Computer Science from Dartmouth College.

Try Modern Treasury

See how smooth payment operations can be.

Talk to sales