Skip to main content

Upgrading

For most self-hosted installations the upgrade procedure is:

  1. Back up your PostgreSQL database. Migrations are forward-only — there is no automated rollback. If a migration fails or behaves unexpectedly, restore from backup.

  2. Pull the new image and restart.

    docker compose pull releval
    docker compose up -d releval

    On startup, the new container takes a Postgres advisory lock, applies any pending migrations, releases the lock, and starts serving traffic.

If a migration cannot acquire a lock quickly enough, typically because long-running application transactions are still holding row locks against tables it needs to alter, startup fails fast rather than wedging the app. Retry after the contention clears.

Decoupling migrations from app startup

Production deployments that prefer to run migrations as an explicit step, for example, to roll back to the previous image if migrations fail without losing the old container, can do so via the migrate subcommand. It connects to the database in ConnectionStrings__Postgres (or passed via --connection) and exits 0 on success, non-zero on failure, so it slots into any CI/CD pipeline that gates the next step on its exit code.

docker run --rm \
-e ACCEPT_EULA=Y \
-e ConnectionStrings__Postgres="Host=postgres;Database=releval;Username=postgres;Password=password" \
releval:next-version migrate

Then start the new app version with MigrateOnStartup=false so it skips the in-process migration step:

environment:
- ACCEPT_EULA=Y
- MigrateOnStartup=false
# ... other config