# Upgrades

> Pin a release, move to a new one with a short maintenance window and roll back if it fails.

Source: https://docs.grovs.io/docs/self-hosting/operate/upgrades

This procedure is for the Compose installer and cloud VMs. Railway, Render, Coolify, Dokploy, Easypanel and CapRover each have an **Upgrades** section in their [platform guide](https://docs.grovs.io/docs/self-hosting/platforms). Run the commands from the install directory: `./grovs` for the installer, `/opt/grovs` as root on a cloud VM. For a local trial, replace `--profile standalone` with `-f docker-compose.yml -f docker-compose.local.yml`.

## Pin the version

`GROVS_VERSION` in `.env` selects the tag for both `ghcr.io/grovs-io/backend` and `ghcr.io/grovs-io/dashboard`. Setup and the installer write a numbered release there, such as `2.3.1`.

| Value              | Behavior                                                                                                                                                     |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| A numbered release | Recommended for production. Nothing changes until you edit it.                                                                                               |
| `latest`           | Takes the newest stable images on the next pull. See [Images and releases](https://docs.grovs.io/docs/self-hosting/configure/images#follow-the-latest-tags). |
| Unset              | Compose falls back to `latest`                                                                                                                               |

Check what the stack will run:

```bash
docker compose --profile standalone config --images
```

## Before you upgrade

1. Read the [release notes](https://github.com/grovs-io/self-host/releases) of every release between your version and the target.
2. Write down the current `GROVS_VERSION`. You need it to roll back.
3. Take a fresh backup with the [backup script](https://docs.grovs.io/docs/self-hosting/operate/backups#backup-script) and keep it until the new version has run cleanly.

## Upgrade

### 1. Pick the version

Print the latest completed release without touching your installation:

```bash
GROVS_RELEASE_URL="$(curl -fsSL -o /dev/null -w '%{url_effective}' https://github.com/grovs-io/self-host/releases/latest)"
printf 'GROVS_VERSION=%s\n' "${GROVS_RELEASE_URL##*/}"
```

Set the `GROVS_VERSION` line in `.env` to that value.

### 2. Pull, migrate and restart

Clear any shell override so Compose reads the saved value, then run:

```bash
unset GROVS_VERSION
docker compose --profile standalone config --images
docker compose --profile standalone pull
docker compose --profile standalone stop dashboard web worker-1 worker-2
docker compose --profile standalone run --rm migrate
docker compose --profile standalone up -d
docker compose --profile standalone ps -a
```

The application is down between `stop` and `up`.

### 3. Verify

Check `https://<API_HOST>/up`, log in, open a link and confirm new analytics arrive. See [Monitoring](https://docs.grovs.io/docs/self-hosting/operate/monitoring).

`pull` also refreshes the supporting images within their tags: `postgres:16-alpine`, `redis:7-alpine`, `clickhouse/clickhouse-server:25.3` and `caddy:2-alpine`. The upgrade changes images only; your Compose file, Caddyfile and `.env` stay as they are.

## Migrations

`migrate` runs `db:prepare` for PostgreSQL, the seed, and the ClickHouse setup. It also runs on every `up` that recreates it, and it is safe to repeat. The application services start only after it exits with code 0.

If it fails, the application stays stopped. Read the error before you do anything else:

```bash
docker compose --profile standalone logs migrate
```

Fix the cause and run `migrate` again, or roll back.

## Roll back

Set the previous version again. If `migrate` ran on the new version, restore the backup you took before the upgrade too: the database schema has already moved forward.

### 1. Stop the application

```bash
docker compose --profile standalone stop dashboard web worker-1 worker-2
```

### 2. Pin the previous version

Set `GROVS_VERSION` in `.env` back to the version you wrote down, then pull it:

```bash
unset GROVS_VERSION
docker compose --profile standalone pull
```

### 3. Restore the data

Skip this step only if `migrate` never ran on the new version. Otherwise follow [Restore](https://docs.grovs.io/docs/self-hosting/operate/backups#restore) from **Start the data stores** through **Restore uploads** with the pre-upgrade backup. Data written after that backup is lost.

### 4. Start

```bash
docker compose --profile standalone up -d
docker compose --profile standalone ps -a
```

## Rules

- Setup and the installer keep an existing `.env`. Edit its version explicitly, and use this procedure rather than the installer for upgrades.
- Never regenerate secrets or encryption keys during an upgrade.
- Keep the backend and dashboard on the same version.
- A restart alone does not fetch a new image.
