Skip to content
PreviewThe Windows download and the public source are in preparation. Request early access.
9400How it works

Backups and restore

A snapshot that proves itself: how to back up on each way of running it, and what a restore re-checks.

Shipped6 min readChecked October 26, 2026

A backup you have never restored is a hope. Here a backup is tested by loading it into a scratch database and re-checking that the ledger still balances.

What to keep

A complete copy is three things, kept together but stored separately where it matters.

  • The database. Every entity's books.
  • The documents. Uploaded files live outside the database, under DOCUMENT_STORAGE_ROOT. A database backup does not contain them.
  • The credentials key. LEDGER_CREDENTIALS_KEY decrypts the integration keys you saved in Settings. A database backup is useless for those without it, and the key must not live only next to the backup.

Encrypt backup storage and any offsite copy, set a retention period, and test a restore in a scratch environment. The application does not encrypt PostgreSQL records or documents for you.

From source

npm run db:backup writes a consistent logical snapshot of every table to the backups/ folder. It reads inside one serializable, read-only transaction, so the copy is a single point in time and takes no write locks. The folder is gitignored, so you can point a sync tool such as OneDrive at it.

npm run db:restore proves the backup. It rebuilds the schema in a scratch database, loads the snapshot, re-applies the triggers and re-checks that posted debits equal credits and that entity and account counts match. It prints PASS or FAIL and exits non-zero on failure. It never touches your live database.

Terminal
npm run db:backupnpm run db:restore

With no argument, restore uses the latest backup. To restore a particular one, pass its folder name after --.

Back up before risky work

Take a backup before a migration or any bulk change, and prove it restores. Never run the reset or recreate commands on books you care about: they drop the database.

The snapshot covers the database only. Copy your document folder and store the credentials key separately.

On Windows

Ledger protects every upgrade for you. When the app version changes, it takes a pg_dump backup, restores it into a scratch database, checks that posted entries balance, migrates only the copy and switches over after a second check. The backup carries a .dump.verified.json receipt. The old database stays in the cluster as ledger_previous_*.

That covers the database during an upgrade. It does not cover documents or the credentials key, and nothing is copied off your machine.

For a complete manual backup:

  1. Close Ledger and confirm that it has stopped.
  2. Copy the entire state folder, %LOCALAPPDATA%\Analytical Ledger, to encrypted offline storage.
  3. To restore, close Ledger and put that complete copy back. Keep the failed state separately for diagnosis.

Keep the state folder whole, including secrets.json. There is no scheduled or off-machine backup service in the Windows package, so decide how often you copy it. Install on Windows has the layout.

On a hosted instance

The operator runs backups for you. In the hosting kit's defaults, a backup service creates a verified recovery set at 02:30 UTC every night and keeps 30 days locally. Verification includes an actual restore into a scratch database that checks parity, constraints and triggers, ledger balances and document hashes.

Local backups alone do not survive the loss of the machine. An offsite copy is a separate decision that you and the operator make before activation, and no offsite provider is switched on silently.

Ask your operator for:

  • the retention period and the offsite destination
  • a restore drill at least monthly, with the result recorded
  • the age of the last local and offsite backup

An operator runs a drill like this on the server:

Operator
bash deploy/hosted/backup-verify.sh <slug>

Run a restore drill

Do this on a schedule, not for the first time in an emergency.

  1. Take a fresh backup.
  2. Restore it somewhere that is not your live system: the scratch restore that npm run db:restore performs, or an isolated stack.
  3. Read the verdict. A pass means posted debits equal credits and the counts match.
  4. Open the restored books and spot-check a report you know.
  5. Confirm you can also restore the documents and the credentials key that go with it.
  6. Record the date and the result.

Never run a live restore over the production database without explicit approval.

Backups and restore | Analytical Ledger