Actual Budget
Local-first envelope budgeting with an optional sync server you can encrypt end to end
Actual is a zero-based envelope budgeting app where the budget lives on your device as a local database and the server exists only to relay changes between your devices. It replaces YNAB or Mint for people who want the app to keep working when the server does not.
Our verdict on Actual Budget#
Actual is local-first in a way that changes what your server is actually for. The budget lives in your browser or desktop app and every edit applies locally first; the sync server on port 5006 holds server-files/account.sqlite (hashed passwords, the budget file list, session tokens) and your budgets as opaque blobs in user-files/, then relays changes. Turn on end-to-end encryption and it keeps relaying but can no longer read anything. That is the tradeoff people get backwards. The server login password can be reset without data loss; the encryption password cannot be reset, recovered or brute-forced. Lose it and your last local copy, and the blobs on the server are noise. Encryption is also one-way, you cannot switch it off, and bank sync tokens sit on the server outside it. Releases are monthly and date-versioned: 26.9.0 landed 1 September 2026 and moved images to Node 24.
Who Actual Budget is for#
Choose it if
- A YNAB refugee who wants envelope budgeting and is content to reconcile by hand
- Anyone who wants the app to keep working offline or with the server down, which it genuinely does
- People who want the server to hold nothing readable, since encryption is per budget file and per password
- A household sharing one budget across a laptop and two phones
Look elsewhere if
- You expect automatic bank feeds everywhere: GoCardless and SimpleFIN cover parts of Europe and North America and need their own credentials
- You cannot commit to storing an encryption password somewhere you will still have it in five years
- You want a double-entry ledger, multi-currency accounts or business-grade reporting, which is Firefly III territory
What running it actually looks like#
One container, no database service. Pull ghcr.io/actualbudget/actual or actualbudget/actual-server from Docker Hub, publish 5006, and mount one volume at /data; the server creates server-files/ and user-files/ under it on first start. Setup is setting a server password on first visit. ACTUAL_DATA_DIR, ACTUAL_SERVER_FILES and ACTUAL_USER_FILES relocate those paths if you need them elsewhere. Watch the upload ceilings, because they bite later rather than on day one: ACTUAL_UPLOAD_FILE_SYNC_SIZE_LIMIT_MB defaults to 20 and the encrypted equivalent to 50, and a long-lived budget can reach them, which presents as sync failures and not as a size warning. 26.9.0 moved container images to Node 24 and dropped 32-bit ARM from the Ubuntu images; use the -alpine tag on those boards.
Resource profile#
- Memory
- 120 MB idle, around 250 MB in ordinary use. A small Express server that mostly moves blobs, so the number tracks concurrent syncing clients rather than budget size. The heavy lifting happens in your browser or desktop app, not here.
- CPU and acceleration
- Almost nothing at rest. Syncing is short bursts of encode and decode; the reports and budget math all run client-side, so a bigger budget slows your laptop, not the server.
- Storage growth
- Small and slow-growing, except that Actual stores every mutation in the budget file, so files grow steadily even when transaction count does not. A sync reset compacts that history back down.
- Operational load
- 2 of 5, Light. One container, one volume, no database service, and the app survives the server being down because every device holds a full copy. It is a 2 rather than a 1 because restores need a sync reset in the right order, and end-to-end encryption adds a secret that is not on the disk you are backing up.
Figures describe a small single-household install and are the working assumptions behind our stack planner. Your numbers will differ with library size, user count and hardware. See methodology.
Data and backup surface#
Back up /data, which is two things: server-files/account.sqlite holding hashed passwords, the file list and session tokens, and user-files/ holding each budget as a binary object. If end-to-end encryption is on, those objects are unreadable without the password, so the password is part of the backup whether you treat it that way or not. Also export from the app itself (Settings, Export Data) on a schedule: that produces a readable archive independent of the server, and it is the only artifact that survives losing both the server and the encryption password. After restoring server data, expect to run a sync reset so devices stop reconciling against newer history.
Derived backup shape
SQLite backup. sqlite3 <db> ".backup out.db" while running, or stop the container and copy. A live cp of a WAL-mode SQLite file can restore corrupt.
Traps and surprises#
A lost encryption password is a lost budget
End-to-end encryption is a second password on top of the server login, and the key is derived from it on your device. The server cannot read the data, cannot reset the key and cannot help. If you still hold a local copy you can reset the key, which forces a sync reset and re-uploads from that device. If you hold neither, the files in user-files/ are unrecoverable. People confuse this with the server login password, which can be reset with no data loss at all.
Encryption is one-way and bank tokens sit outside it
You cannot turn end-to-end encryption back off. Getting to an unencrypted file means exporting from the app and importing into a fresh file. Separately, bank sync credentials for GoCardless or SimpleFIN are stored on the server and are explicitly not covered by the encryption, so an encrypted budget still leaves live banking connections on that disk in a form the server can use.
Budget files grow until you reset sync
Actual stores every mutation in the budget file by default, so the file grows steadily even when the number of transactions does not. Eventually it collides with the 20 MB sync upload limit and large restores start failing. The fix is Settings, advanced, Reset Sync, which compacts the history into one version and issues a new sync id. Every other device then has to revert, which deletes its local copy and re-downloads.
Restoring without a sync reset undoes the restore
Because the server holds change history, restoring an older local file and letting it sync will pull you straight back to where you were before. The documented order is: restore, then reset sync from the restored device so it becomes the authoritative version, then revert every other device. Do it from the device with the most complete data, because a reset discards unsynced changes held anywhere else.
The edge Docker tag was renamed to nightly
26.6.0 renamed the pre-release image tags: edge became nightly and edge-alpine became nightly-alpine. If you were tracking edge, your image quietly stopped receiving updates rather than failing in any visible way, and you can sit months behind without noticing. The same release deprecated rule action templating in favor of formulae, which will be removed in a later version.
Specifications#
- Category
- Tasks, recipes and personal finance
- Licence
- MIT (Permissive)
- Written in
- TypeScript / JavaScript (React and Node.js)
- First release
- 2022
- Maturity
- Stable
- Datastore
- SQLite on the client; the server keeps account.sqlite plus per-budget binary files
- Default ports
5006- Ships as
- docker, docker compose, node source install, desktop app with embedded server
- arm64 builds
- Yes
- Identity
- Native OIDC. OpenID or OAuth2 login is built in and marked preview, configured in `config.json` or the admin UI; it is also the prerequisite for multi-user.
- Replaces
- YNAB, Mint, Quicken, Monarch Money
- Project site
- actualbudget.org
- Source
- github.com/actualbudget/actual
- Documentation
- actualbudget.org/docs
Alternatives to Actual Budget#
Everything else in tasks, recipes and personal finance, closest in operational weight first.
| Tool | Ops load | Idle RAM | Licence |
|---|---|---|---|
| Mealie | 2, Light | 300 MB | AGPL-3.0-or-later |
| Vikunja | 2, Light | 70 MB | AGPL-3.0-or-later |
| Firefly III | 3, Moderate | 250 MB | AGPL-3.0-or-later |
| PLANKA | 3, Moderate | 220 MB | PLANKA Community License (Fair Use License 1.1) |
| grocy | 1, Set and forget | 40 MB | MIT |
Where Actual Budget comes up elsewhere#
Head to head
Migration guides
Sources#
Facts on this page were checked against the project's own material. Where a number is our own estimate rather than a published figure, the text says so.
- Official documentation, syncing and end-to-end encryption
- Official documentation, server configuration and data paths
- Official documentation, Docker install, tags and volumes
- Official release notes, current version and Node 24 change
- Announcement, actual-server repository merged into the monorepo
- Project repository and MIT licence
Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.