Busabase

Upgrading

How to move to a newer version, what happens when a migration fails, and why rolling back means restoring a backup rather than downgrading.

Before you start

Take a backup. Not as ceremony — as the actual rollback plan. See below for why there is no other one.

Compose

./backup.sh /var/backups/busabase
docker compose pull
docker compose up -d

migrate runs first, to completion, before the app starts. If it fails, it exits non-zero and the app never starts: condition: service_completed_successfully sees to that. You get a stopped deployment with a clear reason in the logs, not a running one against a half-migrated schema.

docker compose logs migrate

The output names the failing SQL statement and the database error, but not the migration file it came from. To find the file, grep the migrations directory for the statement:

docker compose run --rm --entrypoint sh migrate -c \
  "grep -rl 'this_table_does_not_exist' apps/busabase-cloud/src/db/migrations"

Send that file with a support bundle rather than hand-patching the schema — a partially applied migration is a state we can fix from the file, and one that is much harder to fix after someone has edited tables directly.

All-in-one

docker pull busabase/busabase-premium-allinone:trial
docker rm -f busabase
docker run -d --name busabase \
  -p 3000:3000 \
  -v busabase-data:/data \
  --restart unless-stopped \
  busabase/busabase-premium-allinone:trial

The -v busabase-data:/data is what makes this an upgrade rather than a fresh install. Same volume name, same data. Omit it and you get a brand-new empty instance that looks like your data was deleted.

Migrations run at start-up here too, and a failure is fatal: the container stops instead of serving requests against a schema it does not understand.

Rolling back

There is no downward migration path. A migration that has added a column does not have an inverse that knows what to do with the rows written since.

Rolling back therefore means: run the previous image tag, and restore the backup you took before upgrading. That is the entire procedure, and it is why the backup step is not optional.

BUSABASE_IMAGE=busabase/busabase-premium:<previous-tag> docker compose up -d
# then restore per /docs/self-hosted/backup-restore

Checking it worked

curl -s http://localhost:3000/api/health

The version field in the response tells you which build is actually serving traffic — worth checking rather than assuming, particularly on a host that had an older image cached.

On this page