I am building a NestJS ledger where money can move a thousand times a second and never once go missing
Most systems that handle money store a balance the same simple way, one number sitting on an account record. Add money, the number goes up. Take money, the number goes down. It works fine until two requests try to touch
Most systems that handle money store a balance the same simple way, one number sitting on an account record. Add money, the number goes up. Take money, the number goes down. It works fine until two requests try to touch that same number at almost exactly the same instant, or until someone needs to know exactly what happened to an account three months ago and finds nothing but the current number staring back at them, no history, no explanation, no way to prove anything.
I am building a ledger that refuses to work this way. The goal is simple to say and hard to actually pull off, money can move through this system a thousand times a second, under real concurrent load, and it should be structurally impossible for a single dollar to quietly disappear, get counted twice, or get rewritten without a trace. Here is what that actually means under the hood, and how NestJS is being used to make it real.
Stop storing a balance, start storing history
The first decision was to throw out the idea of a balance column entirely. Instead of one number that gets overwritten every time something happens, every single movement of money becomes its own permanent, unchangeable entry. Nothing ever gets updated. Nothing ever gets deleted. If a mistake happens, a new entry gets added to correct it, the old entry stays exactly where it is, forever part of the record.
A balance is no longer something the system stores. It is something the system calculates, by adding up every credit and subtracting every debit for that account. That single change is what makes the whole ledger honest. There is no shortcut where a bug or a rushed fix can quietly overwrite what actually happened.
Every transaction is two entries, not one
Real accounting does not let money simply appear or disappear, it only moves. So every transaction in this system writes two entries at once, a debit on one account and a credit on another, and both are required to exist together inside the same atomic database transaction.
If either entry fails to save for any reason, the whole transaction rolls back and neither entry exists. There is no version of this system where money leaves one account without landing in another, since both entries are forced to succeed or fail together.
Making a thousand requests a second safe
Recording history correctly solves honesty. It does not automatically solve speed under real concurrent pressure. If a thousand transfer requests hit the same account close together, something has to stop two of them from both reading an outdated balance and approving a transfer that should have been rejected. This is done with a database level lock at the exact moment an account is read for a transfer.
Once one request has this lock, every other request touching the same account has to wait its turn. Nobody gets to act on a stale balance, because the database itself refuses to let a second request read until the first one has finished and committed its change.
Making the danger visible, not just theoretical
Explaining a race condition in words only goes so far. Alongside the actual API, I am building a small live control panel served directly from the NestJS app itself, where two transfer requests can be fired at the same account at the exact same moment on demand. Watching the lock actually queue the second request and force it to wait, in real time, makes the whole problem concrete in a way that reading about it never quite does.
Firing this endpoint twice at once against the same account shows exactly what the lock is protecting against, one request succeeds, the other either waits and succeeds against the updated balance, or correctly fails if the funds are no longer there.
The bigger picture
None of this is about writing clever code for its own sake. Every decision here exists to answer one plain question honestly, if a thousand people try to move money through this system at the exact same second, can any single dollar end up in the wrong place, or vanish entirely. Immutable entries instead of a balance column, paired debits and credits inside one atomic transaction, and row level locking at the exact point of contention, together those three things are what let the answer stay no, even under real pressure, not just in a calm, empty test environment.
This project is still being built, and there is more to add, idempotency keys to protect against retried requests, and a proper reconciliation layer to catch anything unexpected over time. But the core of it, the part that has to be right before anything else matters, is already standing on solid ground.
If you are building anything where money, or any value that cannot afford to quietly disappear, moves through your backend, this is exactly the kind of foundation I care about getting right.
I am Peace Melodi, a backend software engineer. If you want your business to scale big, comfortably handling millions of users without breaking, with strong scalability and security in place, feel free to reach out.
LinkedIn: https://www.linkedin.com/in/melodi-peace-406494368
GitHub: https://github.com/PeaceMelodi
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.


