Skip to content

Upgrading and Backups

Before you upgrade or move Actual Bench, back up the volume containing ACTUAL_BENCH_DB_PATH. The default location is /data. This database holds Actual Bench sessions, flows, saved queries, exchange rates, and optional encrypted credentials.

DataWhereBack up?
Actual budget dataYour Actual ServerYes - by Actual, or by Actual Bench’s own Backups
Actual Bench metadata/data volume (SQLite)Yes
ConfigurationYour Compose file / environmentYes
SYNC_VAULT_KEYYour secret managerYes - store it separately and safely
Remembered-server passphraseKnown by the userYes, separately - the database cannot recover it
Browser session stateThe browserNo (transient; unlock or reconnect after restart)

That database holds no budget data and no plaintext credentials. It can hold the two encrypted opt-ins: remembered-server secrets, and unattended-sync credentials.

  1. Read the release notes for the target version.
  2. Record your current version (shown in the sidebar footer).
  3. Back up /data (see Backup).
  4. Back up your Compose file and environment configuration.
  5. Ensure SYNC_VAULT_KEY is safely retained (needed to keep unattended credentials usable).
  6. If you use remembered servers, confirm the user still knows the vault passphrase.
  7. Upgrade to a pinned :<version>, not a moving tag. Then you know what you got.

Docker Compose:

Terminal window
docker compose pull
docker compose up -d

Docker CLI:

Terminal window
docker pull xrous/actual-bench:1.2.4
docker stop actual-bench && docker rm actual-bench
docker run -d \
--name actual-bench \
--restart unless-stopped \
-p 3000:3000 \
-v actual-bench-data:/data \
xrous/actual-bench:1.2.4

Name the exact version. latest today and latest tomorrow are not the same image.

Change the tag to latest or a pinned version and recreate the container. Keep the same metadata volume and everything comes with you.

  • Migrations run on boot, automatically, when a newer image meets an existing database.
  • Check the result on App Health: the Schema row shows the current and latest version, and Writable should be Yes.
  • If a migration fails, stop. Do not keep writing to a half-migrated database. Restore the backup you took and work out what happened before trying again.
  1. The app loads and shows the new version in the sidebar footer.
  2. App Health: Writable = Yes, Schema current, Persistence as expected.
  3. Your sync flows and run history are present.
  4. Remembered servers are still listed. The vault will be locked - that is correct, someone has to unlock it.
  5. If you use unattended sync, its scheduler section on App Health looks healthy.
  • Rolling the image back to the previous :<version> is easy.
  • Rolling the database back is not. A newer version may have migrated the schema, and the old image may refuse to read it. That is what the pre-upgrade /data backup is for.
  • After a failed migration, restore. Do not guess.

Let Bench do it. A backup rule set to copy Bench settings snapshots this database on a schedule, opens the copy to check it reads, and puts it wherever you point it. It uses SQLite’s VACUUM INTO, so the copy is safe to take while Bench is running and arrives as a single file with no -wal to reunite.

By hand: back up the /data volume, or at minimum the SQLite file at ACTUAL_BENCH_DB_PATH.

Back up your Compose file and environment too. Keep SYNC_VAULT_KEY somewhere else entirely, in your secret manager.

  1. Stop the container.
  2. Restore the metadata files to the /data volume with correct ownership/permissions.
  3. Restore your environment configuration.
  4. Provide the same SYNC_VAULT_KEY as before.
  5. Start the container and verify App Health.
  6. Lost or changed the vault key? The unattended credentials cannot be decrypted. Re-enrol each flow.
  1. Back up /data and your configuration on the old host.
  2. Restore /data on the new host with correct permissions.
  3. Recreate the container with the same image :<version> and environment.
  4. Provide the same SYNC_VAULT_KEY.
  5. Verify App Health and re-enroll any unattended credentials if the key changed.
  • Everything is empty - /data is not mounted, or points somewhere new. Check the mount and ACTUAL_BENCH_DB_PATH.
  • Not writable - volume ownership or permissions. App Health says so plainly.
  • Migration failed - restore, then investigate.
  • The old image cannot read the new database - go forward again, or restore the backup that matches it.
  • Unattended credentials fail after a move - the vault key is different. Re-enrol the flows.