TigerBeetle vs PostgreSQL Performance: Benchmark Harness, Cloud Tests

Mon, 31 Aug 2026 15:20:00 +0000
Database, PostgreSQL, Tigerbeetle

A few months ago, we tested the performance of TigerBeetle and PostgreSQL in local benchmarks. The test replicated the typical workflow for TigerBeetle’s use case, namely, double-entry bookkeeping to create transfers.

We have seen that in the local setup, TigerBeetle was almost 3 times faster than the fastest PostgreSQL approach, but we still have the question of whether that is also the case when deployed in a cluster setup on dedicated servers. That is what we will try to find out.

As usual, the benchmarks’ code is available on GitHub if you’d prefer to explore and run the tests yourself.

Quick reminder: PostgreSQL schema

TigerBeetle has a fixed schema that supports only double-entry bookkeeping. There are three main entities: ledgers, accounts, and transfers. A transfer always involves two accounts: one is credited, while the other is debited. As mentioned above, creating a transfer is the main database operation. Here’s a similar schema we use for this test in PostgreSQL:

CREATE TABLE IF NOT EXISTS accounts (
    id BIGINT PRIMARY KEY,
    balance BIGINT NOT NULL DEFAULT 0,
    CONSTRAINT balance_non_negative CHECK (balance >= 0)
);

CREATE TABLE IF NOT EXISTS transfers (
    id BIGSERIAL PRIMARY KEY,
    source_id BIGINT NOT NULL REFERENCES accounts(id),
    dest_id BIGINT NOT NULL REFERENCES accounts(id),
    amount BIGINT NOT NULL,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT amount_positive CHECK (amount > 0),
    CONSTRAINT different_accounts CHECK (source_id != dest_id)
);

CREATE INDEX IF NOT EXISTS idx_transfers_source ON transfers(source_id);
CREATE INDEX IF NOT EXISTS idx_transfers_dest ON transfers(dest_id);
CREATE INDEX IF NOT EXISTS idx_transfers_created_at ON transfers(created_at);

We will test 2 strategies for creating transfers in PostgreSQL (implicit locking and explicit locking). All of them can be found here. Since we described them in the last post, we will not repeat them here. If you need a reminder, visit our post about local tests.

Performance benchmark in the cloud

Last time we ran locally, one database instance and one client. For more real-world scenarios, we will run a cluster for each database and 5 client instances. TigerBeetle recommends six nodes across three cloud providers; we used three for this test to match the PostgreSQL setup, configured for its usual leader + 2 replicas consensus. Likewise, we used a similar setup for PostgreSQL with one primary and two synchronous standbys (quorum commit, so transactions are acknowledged only after they’re durable on primary and at least one standby).

These benchmarks were performed on Google Cloud Platform. In addition to the mentioned instances for clients and the database, we also have one node running our monitoring stack with Prometheus and Grafana.

For clients, we used n2-standard-2 (2 vCPUs, 8 GB of RAM) instances, and for the database, we used n2-highmem-4 (4 vCPUs, 32 GB of RAM) instances. You can check all the infrastructure defined in the /terraform directory of our repo.

Measurements and variables

Before discussing the methodology and results, let’s talk about what we want to measure and the variables we can control. Let’s start with variables:

target_rate is the total number of...