# Upgrades

Choose compatible images and roll back safely


Upgrade a self-hosted installation without losing data or plugin compatibility.

Back up first; see [Database Migrations](https://erxes.io/docs/self-hosting-migrations). For runtime settings, see [Configuration](https://erxes.io/docs/self-hosting-configuration). For the deployment this upgrades, see [Self-Hosting](https://erxes.io/docs/self-hosting).

## How releases and images are tagged

erxes versions are cut with `release-it` (`pnpm release`): [.release-it.json](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/.release-it.json) tags the release commit as `<version>` (`tagMatch: 3.*`) and updates [CHANGELOG.md](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/CHANGELOG.md) from conventional commits. Tag pushes then trigger [release.yml](https://github.com/erxes/erxes/blob/f91e8c6f4714c910a32c6b6e14fe085f6435c89e/.github/workflows/release.yml), which re-tags a fixed matrix of Docker images (`erxes/erxes-next-core-api`, `erxes/erxes-next-gateway`, `erxes/erxes-next-ui`, `erxes/erxes-next-logs`, `erxes/erxes-next-automations`, all eleven `erxes/erxes-next-<plugin>_api` images, plus `erxes/frontline-widgets`, `erxes/posclient-front`, and `erxes/help-center`) from `:latest` to `:<version>` using `docker buildx imagetools create`. `erxes/erxes-next-migrations` is published by its own CI workflow but is **not** in the release matrix, so it has no `:3.1.x` tag; pin it by `latest` or digest.

So a released version **does** produce matching `:3.1.9`-style tags across all core and plugin images, but each tag aliases whatever `:latest` was at release time. Between releases, CI also publishes floating `latest` plus per-service tags (`YYYYMMDD-<short-sha>` for APIs and services, full commit SHA for the gateway, branch/SHA/semver metadata tags for UI and apps). Prefer an explicit version tag or digest over `latest` so rollback is a config change, not a guess.

Plugin **frontends** are not images: the `ci-ui-*` workflows sync each `*_ui` build to the `plugins.erxes.io` CDN under `latest/` or the release tag. Enabling a plugin version whose UI assets were not published breaks its navigation; see [Frontend & Plugin Loading](https://erxes.io/docs/architecture-frontend).

## Reading the changelog: 3.1.6 to 3.1.9

`CHANGELOG.md` is the source of truth for what each release changed. For the 3.1.6 to 3.1.9 jump:

- `3.1.7` added OAuth scope-per-plugin-module fixes, a compact `user` header with a 64 KB header budget, document locking, milestone/GitHub-issue sync, and a call-widget cache control.
- `3.1.8` fixed call transfer, content Postiz delivery (tenant routing, JWT signing, QEMU-safe builds), MS Dynamics customer checks, and frontline surveys; it added conversation→ticket/deal/task conversion and `CALLPRO_SUBDOMAINS` gating.
- `3.1.9` added "Basic information" system fields in Settings → Properties, member email activity logs, and frontline convert-property visibility.

None of these releases document a required manual migration. The changelog only tells you what each release includes; confirm by diffing `backend/saas-migrations/` and plugin `src/migrations/` directories between your tags, as described in [Database Migrations](https://erxes.io/docs/self-hosting-migrations).

## Upgrade procedure

### 1. Choose a compatible image set

List every image you run (Core UI, gateway, Core API, logs-service, each `*_api`, any apps), pick one version tag or digest for the whole set, and record current references for rollback:

```bash
docker compose images
docker images --digests | grep erxes
```

### 2. Back up and stage

Take a restorable `mongodump` of the application database and `<db>_logs` ([Database Migrations](https://erxes.io/docs/self-hosting-migrations)). Restore it to staging, deploy the candidate image set with the production `.env` shape, run any new migration scripts, and verify login, enabled plugins, automations, file URLs, and customer-facing apps.

### 3. Upgrade production

Announce the window; a single-server Compose update causes a short outage. Update the image references in `.env`, then:

```bash
docker compose pull
docker compose up -d
docker compose ps
```

Wait for Core API to register and the gateway to recompose its supergraph (the `gateway-update-apollo-router` job handles plugins that join after startup). Run migration scripts for the release if it includes them.

### 4. Check it works

Check `/health` on gateway and Core API, the `__typename` GraphQL probe, owner login, and one representative flow per enabled plugin, including the plugin's remote UI (`/get-frontend-plugins` must return reachable `remoteEntry.js` URLs). Keep the previous image digests and the pre-upgrade backup until the new version is stable.

## Rollback

1. Restore the previous image references in `.env` and run `docker compose up -d`.
2. Restore the pre-upgrade database backup **only** if a migration changed stored data and a forward fix is riskier; restoring loses writes made after the backup.
3. Re-verify health, GraphQL, login, and plugin UI loading.

> [!WARNING]
> **Rollback does not undo migrations**
>
> Recreating containers with older images reverts code, not data. If the release ran a data migration, the only safe rollback is the backup taken before it ran.

