All engineering posts
Engineering

Why We Chose TigerBeetle for Our Energy Ledger

Alex Chi
Why We Chose TigerBeetle for Our Energy Ledger

TrueSource is a peer-to-peer renewable energy trading platform. Businesses buy electricity directly from named renewable generators, whether that's a specific wind farm or a local solar installation, and we track every kilowatt-hour from source to socket. The traceability aspect is our product, so if the ledger is wrong, the product is wrong.

When we started designing our settlement system, the question wasn't really "should we build or buy a ledger?" It was more fundamental than that: "what do we trust to be the single source of truth for every financial and energy transaction on the platform?" We chose TigerBeetle, and this post explains why.

The problem we needed to solve

We operate a dual-ledger system. On one side, we track money: platform fees, commodity costs, network charge pass-throughs, and tax, all to six decimal places of precision as required in the UK market. On the other side, we track energy: generation, consumption, distribution losses, transmission losses, and imbalance positions, measured in kWh at six decimal places.

Every half-hour settlement period, our matching engine pairs generators with consumers. Each match produces a set of linked transactions across both ledgers. The energy moves from generator to consumer (with adjustments for loss), and the money moves in the opposite direction (commodity cost, platform fees, pass-through charges). A single settlement period for one customer can produce five to seven transfers per generator, and all of them must succeed or fail together.

At scale, a busy settlement run might need to commit a million transfers. These aren't independent operations. They form linked chains of two, three, or four transfers that represent the two sides of a trade, a loss adjustment, or a multi-leg financial booking. If any leg of a chain fails, the whole chain must fail. If a chain succeeds, the books must always balance.

We evaluated several approaches: a hand-rolled ledger on top of a general-purpose relational database, a blockchain-based system (the obvious suggestion whenever anyone hears "energy trading"), and an off-the-shelf accounting engine. None of them gave us what we actually needed, which was a purpose-built financial transaction engine that enforces double-entry invariants at the database level, handles linked multi-leg operations atomically, and does it fast enough that settlement doesn't become the bottleneck.

What TigerBeetle does for us

TigerBeetle is a distributed database designed specifically for financial transactions. It does one thing, and it does it with extraordinary rigour. Accounts have debits and credits. Transfers move value between accounts. The database enforces that every debit has a corresponding credit, that balances never go negative unless you explicitly allow it, and that transfers between accounts on different ledgers are rejected.

These sound like application-level rules you could implement yourself, and you could. But there's a meaningful difference between "the application checks this" and "the database physically cannot violate this." TigerBeetle enforces invariants the way a type system prevents type errors: not by checking at the boundary, but by making the invalid state unrepresentable.

Linked transfers

The feature that sealed the decision was linked transfers. TigerBeetle lets you submit a chain of transfers where all must succeed or all fail together, atomically. No sagas, no compensation logic, no two-phase commit protocol that you have to implement and test and get right yourself.

In our system, when a consumer is matched with a generator for a half-hour period, the settlement engine emits a chain of linked transfers. For example, a matched trade might look like this:

  • Debit the generator's energy account, credit the platform's matched-volume pool (the energy leaves the generator)
  • Debit the matched-volume pool, credit the consumer's energy account (the energy arrives at the consumer)
  • Credit commodity revenue (the financial P&L entry)
  • Debit commodity cost (the other side of the P&L)
  • Debit the generator's receivable account (what we owe the generator)

All five transfers are linked. If the consumer's account doesn't exist, or if a balance constraint is violated, the entire chain is rejected. The energy ledger and the financial ledger stay in sync because they literally cannot go out of sync. The database won't allow a partial commit.

Idempotency built in

Every transfer has a unique ID. If you submit a transfer that already exists, TigerBeetle returns exists rather than creating a duplicate. This means our retry logic is trivial: if a network timeout occurs after submitting a batch, we resubmit the same batch. Transfers that already committed are acknowledged, and anything that didn't is retried. No deduplication tables, no distributed locks, no "did that actually go through?" uncertainty.

We derive TigerBeetle's 128-bit IDs deterministically from our own identifiers. The same input always produces the same TigerBeetle ID, so there's no mapping table and no extra database read on the write path.

Invariant enforcement at the database layer

Our energy ledger enforces a conservation law: total generation must equal peer-to-peer matched volume plus distribution losses plus transmission losses plus net imbalance. This isn't a report we run after the fact. It's a property enforced by the structure of the accounts and transfers. Every kWh that enters the system through a generator account must exit through a consumer account, a loss account, or an imbalance account. TigerBeetle's double-entry enforcement means this conservation law holds by construction, not by hope.

On the financial side, the same principle applies. Platform fees are booked as revenue. Commodity costs net against commodity revenue. Pass-through charges (DUoS, TNUoS, BSUoS, CCL, VAT) flow through dedicated accounts at cost. The monthly invoice is a roll-up view of the underlying ledger entries, not a separate calculation. If the ledger is correct, and TigerBeetle's invariants ensure it is, the invoice is correct.

Why not a general-purpose database? Why not blockchain?

We use a general-purpose relational database extensively. It's our primary data store, and every account, every transfer, and every piece of business metadata lives there. All application queries are served from it. But a general-purpose database will happily let you insert an unbalanced journal entry if your application code has a bug. It won't stop you from committing half a linked chain if your transaction logic is wrong.

You can build these safeguards in application code, and many companies do. But application-layer invariants have a failure mode that database-layer invariants don't: they can be bypassed. A new developer writes a migration, or a hotfix skips the validation layer, a race condition in the retry logic double-posts a transfer. When the invariant lives in the database, these failure modes simply don't exist.

We run both databases side by side. Our write flow opens a transaction in the relational database, writes transfers as PENDING, submits them to TigerBeetle, then updates the records to COMMITTED or FAILED based on what TigerBeetle accepted. All application queries (balances, trade history, invoices, reports) are served from the relational database. TigerBeetle is the enforcer; the relational database is the query engine. Each does what it's best at.

As for blockchain: the traceability and immutability properties that blockchain promises for energy trading are real requirements for us. We need an immutable, auditable record of every kWh traded. We need to prove which generator supplied which consumer in which half-hour period. But blockchain adds consensus overhead, finality delays, and operational complexity that we simply don't need. TigerBeetle's double-entry ledger gives us the same auditability guarantees, because every transaction is recorded and every balance can be reconstructed from the transfer history, without the distributed consensus tax. We're not running a trustless public network. We're running a regulated energy platform where TrueSource is the trusted operator, and a purpose-built financial database is the right tool for that job.

The engineering culture we admire

We didn't just choose TigerBeetle for the technology. We chose it in large part because of the team behind it and the engineering culture they've built.

The TigerBeetle team publishes their internal engineering standards in a document called Tiger Style. Inspired by NASA's Power of Ten rules for safety-critical code, it sets out principles that most software teams talk about but few actually enforce: safety before performance, correctness as a necessary but insufficient condition, aggressive use of assertions to catch programmer errors early, and a "zero technical debt" policy that sounds idealistic until you realise they actually mean it.

One principle in particular resonates with how we work: "put a limit on everything, because everything has a limit." Our platform has hard limits everywhere, from batch sizes and matching windows to settlement periods and balance thresholds. Tiger Style articulated why that matters better than we could have ourselves. Unbounded anything is a bug waiting to happen.

Deterministic simulation testing

The approach to testing is what truly sets TigerBeetle apart from other databases in this space. They built a deterministic simulator called the VOPR (the Viewstamped Operation Replayer) which runs an entire TigerBeetle cluster inside a single process with all I/O mocked out. Network faults, storage corruption, and process crashes are all injected by the simulator, all reproducible, and all running at roughly 1,000x real time. About 3.3 seconds of VOPR simulation covers what would be 39 minutes of real-world operation.

When we trust TigerBeetle with the invariants of our energy and financial ledgers, we're trusting a system that has been subjected to a level of adversarial testing that very few databases undergo. That matters when the alternative is explaining to Ofgem why your settlement numbers don't add up.

The browser demo

In 2023, the TigerBeetle team did something we thought was brilliant: they compiled the entire VOPR simulator to WebAssembly and put it in a browser, with a graphical game-like frontend. You can visit sim.tigerbeetle.com right now and watch a TigerBeetle cluster process transactions under perfect conditions, then progressively inject network faults and storage corruption and watch the consensus protocol handle it, all visualised in real time.



They described their goal as making something "simple enough for a child to watch, understand and get excited about." That's a remarkable ambition for a distributed database company, and they pulled it off. The demo makes consensus protocols tangible. You can see replicas communicating, watch what happens when one goes down, and see the cluster recover. It turns an abstract distributed systems concept into something you can poke at and break and watch repair itself.

We'd love to build something similar for our own system one day. Imagine an interactive demo where you can watch a half-hourly settlement cycle play out: generators producing energy, the matching engine pairing supply with demand, linked transfers flowing across the dual ledger, and conservation laws holding as energy and money move through the system. A way to make peer-to-peer energy trading tangible to people who've never thought about how electricity markets work.

We're not there yet. Right now we're focused on getting the platform to production. But the TigerBeetle team showed us what's possible when you treat explanation as a first-class engineering problem, and it's an approach we want to adopt.

What we'd tell other teams considering TigerBeetle

TigerBeetle is opinionated. It's not a drop-in replacement for your application database. It doesn't do queries in the traditional sense. You can look up accounts and transfers by ID, but there's no filtering, no aggregation, and no joins. You need a companion database for all of that, and you should choose whichever one works best for your application. The point is that TigerBeetle handles the thing that general-purpose databases are bad at, which is enforcing financial invariants at the storage layer, and you handle everything else with tools that are designed for everything else.

If you have the time, read Tiger Style. Even if you never use TigerBeetle, the engineering principles are worth your time.