Upgrading and Backups
This guide helps administrators upgrade Actual Bench safely and protect its data. The most important
idea: the only server-side state Actual Bench owns is its metadata database under /data — your
budget data lives in Actual Budget, not here.
What needs to be backed up
Section titled “What needs to be backed up”| Data | Where | Back up? |
|---|---|---|
| Actual budget data | Your Actual Server | Yes — but backed up by Actual Budget, not Actual Bench |
| Actual Bench metadata | /data volume (SQLite) |
Yes |
| Configuration | Your Compose file / environment | Yes |
SYNC_VAULT_KEY |
Your secret manager | Yes — store it separately and safely |
| Browser session state | The browser | No (transient; re-enter secrets on reconnect) |
The metadata database holds sync flows, run history, and (if enabled) encrypted unattended-sync credentials. It does not contain your budget data or plaintext Actual credentials.
Before upgrading
Section titled “Before upgrading”- Read the release notes for the target version.
- Record your current version (shown in the sidebar footer).
- Back up
/data(see Backup). - Back up your Compose file and environment configuration.
- Ensure
SYNC_VAULT_KEYis safely retained (needed to keep unattended credentials usable). - Prefer upgrading to a pinned
:<version>rather than a moving tag, for a controlled change.
Upgrade procedures
Section titled “Upgrade procedures”Docker Compose:
docker compose pulldocker compose up -dDocker CLI:
docker pull xrous/actual-bench:1.2.4docker stop actual-bench && docker rm actual-benchdocker run -d \ --name actual-bench \ --restart unless-stopped \ -p 3000:3000 \ -v actual-bench-data:/data \ xrous/actual-bench:1.2.4Pin the exact :<version> you intend to run so the upgrade is deterministic.
Moving from edge to stable
Section titled “Moving from edge to stable”If you were testing edge, switch the image tag to latest or a pinned :<version> and recreate the
container. Keep the same /data volume so your metadata carries over.
Database migrations
Section titled “Database migrations”- Schema migrations run automatically on boot when a newer image starts against an existing metadata 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, do not keep writing. Restore the
/databackup you took before upgrading and investigate before retrying.
Verify after upgrade
Section titled “Verify after upgrade”- The app loads and shows the new version in the sidebar footer.
- App Health: Writable = Yes, Schema current, Persistence as expected.
- Your sync flows and run history are present.
- If you use unattended sync, its scheduler section on App Health looks healthy.
Rollback
Section titled “Rollback”- You can roll the image back to the previous
:<version>. - Be aware that a newer version may have migrated the schema; an older image might not read a
newer database. If that happens, restore the pre-upgrade
/databackup. - After a failed migration, prefer restore from backup over guessing.
Back up the metadata database
Section titled “Back up the metadata database”Back up the /data volume (or at least the SQLite file at ACTUAL_BENCH_DB_PATH, default
/data/actual-bench.sqlite).
Also back up your Compose/environment configuration, and store SYNC_VAULT_KEY separately in your
secret manager.
Restore the metadata database
Section titled “Restore the metadata database”- Stop the container.
- Restore the metadata files to the
/datavolume with correct ownership/permissions. - Restore your environment configuration.
- Provide the same
SYNC_VAULT_KEYas before. - Start the container and verify App Health.
- If the vault key was lost or changed, unattended credentials can’t be decrypted — re-enroll them per flow.
Move to another host
Section titled “Move to another host”- Back up
/dataand your configuration on the old host. - Restore
/dataon the new host with correct permissions. - Recreate the container with the same image
:<version>and environment. - Provide the same
SYNC_VAULT_KEY. - Verify App Health and re-enroll any unattended credentials if the key changed.
Troubleshooting
Section titled “Troubleshooting”- App started with empty metadata — the
/datavolume isn’t mounted (or points somewhere new); check the mount andACTUAL_BENCH_DB_PATH. - Database not writable — check volume permissions/ownership; App Health shows Writable = No.
- Migration failed — restore the pre-upgrade backup and investigate.
- Old image can’t read the new database — roll forward again, or restore the matching backup.
- Unattended credentials fail after a move — the
SYNC_VAULT_KEYdiffers; re-enroll the flows.
