# Updating

> Update a self-hosted Nodaro by pulling a newer image, pin a release tag, prepare for a major version with a backup, and roll back by restoring that backup.

Source: https://nodaro.ai/docs/self-hosting/updating

**Updating** a self-hosted Nodaro means pulling a newer app image and restarting the app. On the bundled stack, the new database migrations apply themselves at boot, so there is nothing else to run. Before a **major** version, read the release notes and take a backup, because there is no downgrade path.

## Image tags

Every build of the `main` branch publishes the app image, `ghcr.io/nodaroai/nodaro-community`, as `latest` and under its commit. A release adds three version tags.

| Tag | What it means |
| --- | --- |
| `vX.Y.Z`, for example `v2.0.0` | Exactly one build, never moved. Pin it for a byte-for-byte stable install. |
| `vX.Y` | Moves across the patches of one minor version. |
| `vX` | Moves across a whole major version: features and fixes arrive, breaking changes never do. |
| `latest` | Follows `main`: every merged change, released or not, major versions included. |
| `<sha>` | One commit, never moved. The other way to reproduce exactly one build. |

Choose the tag with `NODARO_IMAGE` in `.env`, for example `NODARO_IMAGE=ghcr.io/nodaroai/nodaro-community:v1.23.0`.

## Update the install

To update the app only:

```bash
docker compose -f docker-compose.community.yml pull nodaro
docker compose -f docker-compose.community.yml up -d nodaro
```

To also update the compose file, the scripts in `tools/` and the bundled services:

```bash
git pull
docker compose -f docker-compose.community.yml pull
docker compose -f docker-compose.community.yml up -d
```

If you build the image from source, for example for the Business edition, replace `pull` with `build`. A `pull` would download the published Community image.

Migrations are kept forward-compatible, with new tables and added columns. A destructive change is called out in the release notes. Pin a tag or a commit if you need to be cautious.

## Before a major version

A major version changes the first number, for example from `v1` to `v2`. Major versions are the only releases allowed to change environment variables, the compose topology or behavior you may depend on.

1. Read the release notes on [GitHub](https://github.com/nodaroai/app.nodaro.ai/releases).
2. Take a backup with `tools/community-backup.sh`. See [Backups and restore](https://nodaro.ai/docs/self-hosting/backups).
3. Update, then check `/setup`: every card should be green.

## Roll back

There is no migration rollback: the database only moves forward. To return to an earlier version:

1. Restore the backup you took **before** the update: `tools/community-restore.sh <archive>`.
2. Pin the older image, for example `NODARO_IMAGE=ghcr.io/nodaroai/nodaro-community:v1.25.1`. Exact `vX.Y.Z` tags never move.
3. Start it with `docker compose -f docker-compose.community.yml up -d nodaro`.

## With a managed Supabase project

When the migration runner is off, apply the new files in `supabase/migrations/` in filename order **before** you restart onto the new image. A missing migration usually does not stop the API, but the features that need it answer `500` until their tables exist. See [Database](https://nodaro.ai/docs/self-hosting/database#apply-the-migrations-to-a-managed-project).

## Which version you run

The running version is shown in the app sidebar and at `/health`. Click the version for the release notes of the version you run. When a newer release exists, a red dot appears next to the version. The same dialog then shows the newest release notes and the exact upgrade commands, with the backup step first.

The update check sends one anonymous request a day to the GitHub API. A failed check is tried again after 5 minutes, then less and less often, until one succeeds.

| Variable | Default | What it does |
| --- | --- | --- |
| `NODARO_UPDATE_CHECK` | on | `off` disables the check completely. No request leaves the install, `GET /v1/version` answers with the running version only, and the sidebar shows the version as plain text. For air-gapped installs. |
| `NODARO_UPDATE_CHECK_TOKEN` | empty (anonymous) | A GitHub token for the check's reads of the public release list. It needs **no scopes**. |

GitHub allows 60 anonymous requests an hour per outbound address. An install with its own address never needs a token. An install that shares its address with others can find that quota spent by strangers. The version label then falls back to the built-in one, and the release notes stay empty until a retry succeeds. The log line `[update-check] … read failed: HTTP 403 (rate limit: 0 of 60 left…)` is the sign. The token is sent only to `api.github.com` and is never logged.

The compose file does not pass these two variables from `.env`. Add them under `environment:` of the `nodaro` service:

```yaml
nodaro:
environment:
# ...the variables already listed...
NODARO_UPDATE_CHECK: "off"
```

Restart to apply.

## Update a server from GitHub Actions

The repository ships an example workflow, `examples/deploy-host.yml`, that updates a Nodaro server over SSH:

1. Copy it into your own repository, under `.github/workflows/`.
2. Set the repository secrets `DEPLOY_HOST`, `DEPLOY_USER` and `DEPLOY_SSH_KEY`.
3. Adjust the install directory and the compose command in its script to match your server.
4. Run it by hand from the **Actions** tab, and choose the image tag to deploy.

The workflow connects to the server, runs `docker compose pull` and `docker compose up -d`, waits up to 90 seconds for `/health` to answer, then removes old image layers. Never start a production deploy on a branch push, and use separate secret names for each environment.

## Frequently asked questions

### How do I update a self-hosted Nodaro?

Run docker compose -f docker-compose.community.yml pull nodaro, then docker compose -f docker-compose.community.yml up -d nodaro. On the bundled stack, the database migrations apply themselves at boot.

### Which image tag should I pin?

Pin an exact vX.Y.Z tag for a byte-for-byte stable install. vX.Y takes the patches of one minor version, vX takes features and fixes without breaking changes, and latest follows every merged change, majors included.

### Can I downgrade to an earlier version?

Not directly, because the database migrations only move forward. Restore the backup you took before the update, then pin the older image tag. Take a backup before every major version.

### How do I know that an update is available?

The version in the app sidebar shows a red dot when a newer release exists. Click it for the release notes and the exact upgrade commands. The check is one anonymous request a day to GitHub.

### Can I disable the update check for an air-gapped install?

Yes. Add NODARO_UPDATE_CHECK set to off under the nodaro service's environment block in docker-compose.community.yml. No request then leaves the install, and the version shows as plain text.
