pledge

pledge

pledge is a double-entry ledger that runs inside PostgreSQL. You create accounts and move money between them with plain SQL. Every transfer is booked twice, once out and once in, so the books always add up.

Get started Use it from SQL Use it from Django

A quick look #

CREATE EXTENSION pledge;

-- Two accounts. Alice's wallet may never go below zero.
SELECT id FROM pledge.create_account('bank', 'USD');
-- pla_01M730CQFEF2CR8VRK2DCTVZ7P
SELECT id FROM pledge.create_account('alice', 'USD', allow_negative_balance => false);
-- pla_01M730CQFHFJQ9TRR4FW8SYK2Y

-- Move 100 from the bank to Alice.
SELECT * FROM pledge.create_transfer('pla_01M730CQFEF2CR8VRK2DCTVZ7P', 'pla_01M730CQFHFJQ9TRR4FW8SYK2Y', 100.00);

-- Check the balances.
SELECT name, balance FROM pledge.accounts_view ORDER BY name;
 name  | balance
-------+---------
 alice |  100.00
 bank  | -100.00

Try to take out more than Alice has, and the database says no:

SELECT * FROM pledge.create_transfer('pla_01M730CQFHFJQ9TRR4FW8SYK2Y', 'pla_01M730CQFEF2CR8VRK2DCTVZ7P', 1000);
ERROR:  Account (id=pla_01M730CQFHFJQ9TRR4FW8SYK2Y, name=alice) does not allow negative balance
DETAIL:  {"code": "pledge.negative_balance_not_allowed", "account_id": "pla_01M730CQFHFJQ9TRR4FW8SYK2Y"}

Why pledge #

  • Correct by default. Every transfer writes two entries that sum to zero. Each entry stores the account’s running balance, so you can see the balance at any point in history.
  • Safe to retry. Send your own transfer id. If you send the same transfer twice, it’s booked once.
  • Hard to tamper with. The database itself refuses to delete ledger rows or change amounts. You close accounts, you never delete them.
  • Fast. Roughly 1.5 times faster than pgledger per transfer, and about 2 times faster for batches. See Performance.
  • Clear errors. Each failure has a stable code, like pledge.negative_balance_not_allowed, that your app can match on.

pledge runs on PostgreSQL 17 and 18.

Where it comes from #

pledge grew out of pgledger, pgr0ss’s double-entry ledger in plain SQL, which is already in use. pledge keeps its model, rewrites the hot path in Rust, and still benchmarks against it.

pledge itself is young. It works and is validated, including a replay of a real bank’s million transactions, but the API may still change before 1.0. Pin the version you use, and tell us what you run into.

Where next #

Install and set up

Run Postgres with pledge, create the extension, give your app access.

Accounts

Create accounts, stop overdrafts, close accounts.

Transfers

Move money, one transfer or many at once.

Django

Ledger models for your Django project.

Build an exchange

A step-by-step tour of a small currency exchange built on pledge.