Backup and restore
pg_dump the database, archive the uploads volume, keep .env. A Trove KB backup never contains a secret.
Everything Trove KB owns lives in two places: the Postgres database and the uploads volume. Secrets are not among them. Passwords and TOTP seeds stay in your vault, so a Trove KB backup never contains one.
| What | Where | Needed to restore |
|---|---|---|
| Database | pgdata volume, Postgres 16 | Yes |
| Attachments | uploads volume, or your S3 bucket | Yes, unless STORAGE_DRIVER=s3 |
.env | Your secret store | Yes: AUTH_SECRET signs sessions, POSTGRES_PASSWORD opens the database |
secrets/bw_master_password.txt | Your secret store | Only in bw_serve mode |
Back up
# Database, compressed custom format.
docker compose exec -T db pg_dump -U trove -Fc trove > trove-kb-$(date +%F).dump
# Attachments, when STORAGE_DRIVER=local.
docker run --rm -v trove-kb_uploads:/data -v "$PWD:/backup" alpine \
tar czf /backup/trove-kb-uploads-$(date +%F).tar.gz -C /data .
Store .env alongside them. A nightly cron on the host is enough for most installs:
15 2 * * * cd /srv/trove-kb && docker compose exec -T db pg_dump -U trove -Fc trove > /backups/trove-kb-$(date +\%F).dump
Attachments can live on the NAS instead of a local volume: docker compose -f docker-compose.yml -f docker-compose.nfs.yml up -d with NFS_SERVER and NFS_UPLOADS_PATH set. Uploaded files are write-once, read-many, which is what a share is good at; the database stays on local disk because it is hot data.
Restore
docker compose down
docker volume rm trove-kb_pgdata trove-kb_uploads # only when starting clean
docker compose up -d db
docker compose exec -T db pg_restore -U trove -d trove --clean --if-exists < trove-kb-2026-03-01.dump
docker run --rm -v trove-kb_uploads:/data -v "$PWD:/backup" alpine \
tar xzf /backup/trove-kb-uploads-2026-03-01.tar.gz -C /data
docker compose up -d
Migrations run automatically on start, so a dump from an older version is brought up to date by the container it is restored into.
Verify a backup
Restore into a throwaway stack rather than trusting the file:
APP_PORT=3099 docker compose -p trove-kb-verify up -d db
docker compose -p trove-kb-verify exec -T db pg_restore -U trove -d trove --clean --if-exists < trove-kb-2026-03-01.dump
APP_PORT=3099 docker compose -p trove-kb-verify up -d
# Sign in, open a company, then tear it down.
docker compose -p trove-kb-verify down -v
Exports are not backups
The per-company export (JSON and Markdown, from the company page or GET /api/v1/companies/:id/export) is for reading and handover. It leaves out revisions, the audit trail, API keys, and webhook configuration. Use pg_dump for anything you intend to restore from.