Why Database-Layer Double-Entry Is a Bet, Not a Guarantee
An invariant baked into the schema doesn't survive a changing business
You can go too far and design a ledger that’s too rigid.
When you engineer software, there’s a tendency to push the most basic rules of your code as close to the storage layer as possible. The reasoning is that things that must always be true don’t change, and must be the foundation of the rest of the system. Or so the argument goes.
This is a good heuristic. But if that thing you call invariant needs to be modified, or you need to change the database engine as a result of scale, closeness to storage will make the migration more difficult and expensive.
Database invariants either age well, or get rewritten.
It ain’t what you don’t know that gets you into trouble. It’s what you know for sure that just ain’t so.
In ledgers, the most foundational of business rules is double-entry safety. And so, many ledger systems have placed its logic as close to the database as possible.
TigerBeetle takes this argument to its purest expression. Its primitives are not tables. They are Account and Transfer. A transfer “debit a single account and credit a single account.” There is no INSERT INTO transfers that can produce an unbalanced row, because the API does not expose a shape in which an unbalanced posting is a valid input.
Which sounds like a good thing, and it is, unless the world suddenly becomes multi-currency. TigerBeetle is built for speed, but makes multi-currency scenarios unmanageable.
The thing about ledgers is that, although they’re hard to build correctly, there isn’t One Canonical Ledger Design that every ledger must conform to. Every company has nuanced finances, idiosyncratic approaches, tricky and ever changing regulation, and evolving business needs.
TigerBeetle proved that double-entry deserves a primitive. But it didn’t prove that the primitive has to live in the database.
I’m Alvaro Duran, and this is The Payments Engineer Playbook. You’re already subscribed to free newsletters that “teach” you how to get a job as a software engineer.
But you don’t want to get a job; you already have one. What you want is to learn how to be great at your job. Especially as a payments engineer, where stakes are sky-high, and the margin for error is razor-thin.
In The Payments Engineer Playbook, we investigate the technology that transfers money. All to help you become a smarter, more skillful, and more successful payments engineer. And we do that by cutting off one sliver of it and extracting tactics from it.
In today’s article, I’m going to make the case for placing all the ledger’s logic, even its most foundational, in the application layer, and away from the database. When you do that, you’re one bug away from corrupting the books without the database to help you. But the reality is that ledger bugs can’t be prevented by database schemas unless you make these schemas so rigid that you lose the ability to adapt to the needs of the company.
In other words: database safety is an illusion.
Here’s what you can expect in today’s article:
Seeing the tech stack as a business bet
Persistence ignorance as a mitigation mechanism for scale
The only valid way to ensure double-entry safety
Enough intro, let’s dive in.





