Upgrade & Backup
What the server does on startup, and how to back up and upgrade an instance safely.
What's documented server behavior vs. what's a recommendation
The server itself only does one thing relevant here on every startup: it runs its embedded database migration against whatever DATABASE_URL points at, and that migration is idempotent — safe to run again against a database it has already migrated. Everything else on this page — backup cadence, reading release notes, keeping old image tags around — is an operating recommendation, not something the server enforces or reminds you about.
Back up before you touch anything
Two things hold all the state that matters for a self-hosted instance, and the server backs up neither for you:
-
Your PostgreSQL database. This needs an actual database-level backup, not a filesystem copy of a container — the Compose deployment doesn't even bundle a Postgres container to copy, since
apiconnects out to whatever external Postgres instanceDATABASE_URLnames. Use your database's own backup mechanism:pg_dumpagainst that connection string,pg_dump "$DATABASE_URL" -Fc -f tabslate-backup.dumpor your managed provider's built-in backup/snapshot feature if you're not self-hosting Postgres too.
-
Your
.envfile. It holdsJWT_SECRET,DATABASE_URL, and every other credential the server needs — losing it without a copy means regenerating secrets and reconfiguring every provider from scratch, even though no user data was lost.
docker compose down -v removes the named volumes declared in docker-compose.yml — caddy_data and caddy_config, which hold Caddy's cached TLS state. It does not touch your PostgreSQL data, since Postgres isn't one of the containers this Compose file manages. Still, run it deliberately: recreating those volumes means Caddy re-requests a certificate from Let's Encrypt, which is rate-limited per domain.
Upgrading
-
Read the release notes for the version you're moving to before upgrading, since the server doesn't summarize what changed for you.
-
Take the backups above first.
-
Pull the new image and recreate the container:
docker compose pull api docker compose up -d --force-recreate api -
Watch it come up and confirm the migration ran cleanly:
docker compose logs -f apiLook for
database readyin the log output — that line only prints afterdb.Migratehas returned successfully.
Keep a rollback path
Pin or note the image tag/digest you were running before pulling latest, so you can pin back to it (docker compose pull a specific tag, or edit the image: line in docker-compose.yml) if the new version doesn't work out. Combined with a recent database backup, this is what actually makes an upgrade reversible — latest by itself gives you no way to know what you were running before.
Last updated on