Upgrades
An upgrade is a new image started on the same database. The database schema is updated by migrations, which the image applies when it starts.
Read the changelog → Back up → Check out the release → Build and start → Migrations applied → Healthy
Healthy → Previous image: rolling back, after restoring the backup if there were migrations
Knowing when there is a new release
The version the desk runs is at the bottom left of the sidebar, next to the ITSM Engine credit, with Up to date or Update available. For admins it leads to Settings → Updates.
Settings → Updates shows the version, the update status, and every release published on GitHub, newest first, with its release notes:
| Mark | Means |
|---|---|
| This desk | The release this desk runs. |
| Newer | A newer release. |
| Pre-release | A pre-release. It is never offered as the update. |
The daily check
Once a day the desk asks GitHub for the releases of ITSM Engine: a plain request, with nothing about your desk in it. It keeps the answer, so pages never ask GitHub themselves, and it never updates anything by itself.
From the first release on, each release is also published as an image, ghcr.io/nicelab-no/itsmengine:<version>,
tested by upgrading from the release before it. None is published yet, so for now the image is built from source.
- Check now asks right away.
- Check for updates once a day on the same page (or
UPDATE_CHECK=false) turns it off, for example on a server without internet access.
While no release is published, the page says so.
Before you upgrade
- Read what changed between your version and the new one in CHANGELOG.md, at the top of
the repository. New folders under
apps/server/prisma/migrationsmean the database schema changes. - Take a backup of the database.
[!IMPORTANT] Migrations only go forward, so the backup is your way back.
Upgrading the Docker Compose setup
With the recommended setup:
-
Go to
deploy/and take a backup:cd deploysh backup.sh -
Check out the new release:
git fetch --tags && git checkout <new release tag> -
Build and start:
docker compose up -d --build -
Wait until
deskturns healthy, once its migrations are applied:docker compose ps
Compose rebuilds the app image and replaces only the desk container. Postgres, storage and Caddy keep running, and
their data stays in their volumes. The pinned Postgres, storage and Caddy images only change when a release changes
compose.yaml; the release notes say so.
Upgrading the Scale setup
[!IMPORTANT] With Scale, name both compose files in every command, including the backup.
-
Go to
deploy/and take a backup:cd deploysh backup.sh -f compose.yaml -f compose.scale.yaml -
Check out the new release:
git fetch --tags && git checkout <new release tag> -
Build and start:
docker compose -f compose.yaml -f compose.scale.yaml up -d --build -
Check that everything is healthy:
docker compose -f compose.yaml -f compose.scale.yaml ps
What happens during a Scale upgrade
Worker starts with the new image → Worker applies the migrations → Worker healthy → Application servers start with the new image
Compose replaces the application servers together, not one after another. The desk pauses for the few seconds they take to start; agents' pages carry on once they answer, and live updates reconnect by themselves.
PostgreSQL, storage, PgBouncer, Redis and Caddy keep running. A release that changes the PgBouncer or Redis image says so in its notes.
To move between Standard and Scale, see Standard and Scale: the data stays where it is, and nothing needs migrating.
Upgrading
-
Build or pull the new image:
git pulldocker build -t itsmengine . -
Replace the running container with one from the new image, with the same environment:
docker compose up -d deskor
docker stop desk && docker rm deskfollowed by the samedocker runas before. -
On start the entrypoint runs
prisma migrate deploy, which applies the migrations the database doesn't have yet, then starts the server. If a migration fails, the container stops before the server starts; the log shows the failing migration. -
Wait for the health check to pass, then sign in and look around.
Shutdown is graceful: on SIGTERM the old container finishes open requests and stops its job worker. Jobs that
were waiting stay in the queue and the new container picks them up.
Running migrations separately
Run migrations on their own when you run several instances yourself (outside compose.scale.yaml, where the worker
does this), or want migrations as their own deploy step.
-
Set
MIGRATE_ON_START=false. -
If
DATABASE_URLgoes through PgBouncer, setDATABASE_DIRECT_URLfor this run: migrations need a direct connection. -
Run them once with the new image, before starting the new containers:
docker run --rm --env-file desk.env itsmengine ./node_modules/.bin/prisma migrate deploy
Until that has run, the new image's /healthz answers 503. On the server itself, it also lists the migrations it
expects but doesn't find:
{ "status": "error", "database": "ok", "pendingMigrations": ["20261021104447_oauth"] }
so a platform that waits for the health check won't send traffic to it.
Checking the result
GET /healthz answers 200 with "status":"ok" and the number of applied migrations. warnings, if any, list
installation settings that still need attention; they don't block anything (see
troubleshooting).
Rolling back
Prisma migrations have no "down" step. To go back to the previous version:
| The new version had | To go back |
|---|---|
| No migrations | Start the previous image again. |
| Migrations | Stop the desk, restore the database backup taken before the upgrade, and start the previous image. |
[!WARNING] Cases and changes made since the upgrade are lost when you restore, so decide quickly.
An older image started on a newer database still reports healthy, but /healthz lists the migrations it doesn't
know under unknownMigrations. The schema is no longer the one it was built for, and requests can fail. Don't run it
that way.