Swedish for balance
Know your
balance.
Saldo is a calm, private budgeting app for you and the people you share a home with. Every currency, every subscription, every envelope, on a server you control.
- No email needed
- No trackers
- Works offline
- Self-hostable
Spent this month
€1,284.60
On pace for
€2,140.00
83% used, 80% alert sent
- Fi-€13.82
Figma
$15.00 at 0.9213
- Re-€870.00
Rent
Shared · your 60% of €1,450.00
- currencies, converted daily
- 150+currencies, converted daily
- billing intervals
- 6billing intervals
- third-party trackers
- 0third-party trackers
- command to self-host
- 1command to self-host
What's in the ledger
Everything a budget needs, nothing it doesn't.
01
Every currency, one total
Log expenses in more than 150 currencies, from the dollar to the Mongolian tögrög, and see them in yours. Exchange rates are cached daily in your own database, keep working offline from the last known rate, and can be overridden by hand on any transaction.
02
Subscriptions that add up
Weekly, monthly, quarterly, every six months, yearly or a one-off lifetime purchase. Each shows its monthly and annual equivalent cost, a renewal countdown, and can be paused or canceled without losing its history.
03
Envelopes with a heads-up
Give categories a monthly cap. Saldo warns you at 80% and again at 100%, shows whether you're ahead of an even pace, and can roll unused money into next month.
04
Trends you can show anyone
How often and how much you spend per category, how that changes month to month, which weekdays cost the most, and a year-long heatmap. Press Shift + P and every amount disappears while the shapes stay.
05
Your data, portable
Export exactly what you need: a month, a year, a custom range or all time, filtered by category, account or type, personal or household. A clean CSV, or a zip of everything.
06
Sign in your way
Just a username. Use a password (hashed with Argon2id) or passkeys on as many devices as you like, each with its own label. Sessions are listed and revocable.
Recurring costs
The gym bills twice a year. You pay for it every month.
Saldo normalises every recurring cost to a monthly and an annual equivalent, so a semi-annual membership and a weekly lesson sit side by side honestly. Renewals are logged for you on the day they're due.
| Subscription | Billed | Per month | Per year |
|---|---|---|---|
| StreamingMonthly | €13.99/mo | €13.99 | €167.88 |
| GymEvery 6 months | €240.00/6mo | €40.00 | €480.00 |
| Home insuranceQuarterly | €96.00/qtr | €32.00 | €384.00 |
| Domain nameYearly | €18.00/yr | €1.50 | €18.00 |
| Language courseWeekly | €12.50/wk | €54.17 | €650.00 |
| Photo editorLifetime | €89.00 once | - | - |
| Run rate | €141.66 | €1,699.88 |
Home · this month
€2,456.80 shared
Sam pays Alex €368.42
Mark paidHouseholds
Share the rent, not your whole wallet.
Every transaction is either Personal or Shared, and you decide which. Shared costs are split by each member's weight, Saldo tracks who has paid what, and suggests the fewest transfers to settle up. Your personal spending stays invisible to everyone else in the household.
- Invite with a one-time code
- Household budgets, goals and categories
- Settlement history and CSV export
Privacy by construction
Not even the admin can see your numbers.
Isolation isn't just a check in the code. The database itself enforces it with row-level security: the app connects as a role that can only ever read rows belonging to the signed-in person, or rows deliberately shared with their household.
- Admins manage accounts, never balances or transactions
- No analytics, no ads, no third-party scripts
- The only outside request fetches public exchange rates
-- the app role cannot bypass this
alter table transactions force row level security;
create policy saldo_tx_select on transactions
for select using (
user_id = app_user_id()
or (scope = 'shared'
and household_id = any(app_household_ids()))
);Self-host
Your server, your ledger.
Saldo is a single Next.js app and a PostgreSQL database. Run it in Docker anywhere, or natively on Windows with Node.js, no WSL required. The first admin is created from environment variables on first start.
Docker
Postgres included, with a health check. Migrations run on start.
$ cp .env.example .env$ docker compose up -d# open http://localhost:3000Windows, macOS or Linux
Node.js 22+ and PostgreSQL 16+. Works in PowerShell.
$ npm ci$ npm run build$ npm run setup$ npm startRather just try it?
Create an account here. All it takes is a username.