> ## Documentation Index
> Fetch the complete documentation index at: https://bisibility.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Self-hosted upgrades

> Upgrade a self-hosted bisibility installation with the signed distribution manifest.

[Production checklist](/docs/self-hosting#production-checklist)

## Upgrade with a distribution manifest

<Warning>
  v0.5.0 resets the Prisma migration history to one final-schema baseline and is
  for fresh installations only. Existing v0.4.1 and earlier databases do not have
  a supported upgrade path to v0.5.0. Keep those installations on their current
  release; the v0.5.0 `upgrade.sh` fails before changing Compose or PostgreSQL.
</Warning>

Releases whose `distribution-manifest.json` lists the `upgradeScript` artifact
ship `upgrade.sh` as a versioned release asset alongside the manifest.
`distribution-manifest.json` is also included in the tagged source (see
[Production Compose](/docs/self-hosting/docker#production-compose)). Older releases
without that manifest entry do not ship `upgrade.sh` as a release asset; obtain
the script from the matching tagged source tree instead. The distribution
manifest checksums `upgrade.sh` and the other listed release assets; the
manifest plus its listed assets are verified before publication.

The procedure below is the canonical current upgrade path. Migrations are
forward-only; there is no automatic rollback.

### Prerequisites

Before starting, gather the exact target release assets and plan a maintenance
window:

* Download `distribution-manifest.json` and `upgrade.sh` from the GitHub release
  assets for the matching tag.
* Install Docker Compose v2 and Node.js on the operator host.
* Read the changelog for the target release and note schema or environment
  changes. Review `.env.example` against the current `.env` and update
  deliberately.
* Schedule a maintenance window or stop writes before touching the database.
* Never enable demo OTP or demo seeding on a production deployment.

### Backup as rollback

A tested application PostgreSQL backup, matching application secrets, and
applicable Temporal persistence are the rollback mechanism. Create the backup
before starting the upgrade; see
[Backup and restore](/docs/self-hosting/backup-restore). Migrations are forward-only;
an image rollback does not reverse Prisma migrations.

### Verify release assets

When the manifest contains `upgradeScript`, the script verifies the manifest,
target version, and listed images before it touches services or the database.
Run the canonical invocation with the exact target version:

```bash theme={null}
./upgrade.sh --version vX.Y.Z
```

Without `--compose-file`, the script uses `compose.yaml` next to it. To layer
overlays, pass the base file first and repeat `--compose-file` for
`compose.worker.yaml` and `compose.temporal.yaml` in order:

```bash theme={null}
./upgrade.sh --version vX.Y.Z \
  --compose-file compose.yaml \
  --compose-file compose.worker.yaml \
  --compose-file compose.temporal.yaml
```

A manifest, version, or image mismatch returns nonzero and stops the upgrade
before any service or database change.

### Stop services

After verification succeeds, the script pulls the selected release images and
stops `app` and `worker` when the rendered Compose configuration includes them.
It detects the service set from `compose config --services` rather than
assuming a worker service always exists.

### Run migrations

The script runs the one-shot `db-migrations` service with
`prisma migrate deploy` for the full Prisma tree and then all blocking data
migrations before the web app. The migration container's exit code is
propagated: a failed verification or migration returns nonzero and prevents
app/worker restart.

The migration ledger distinguishes completed data work from final completion.
If optional finalization fails, the command exits nonzero and records the
finalization error while leaving the migration unfinished. Rerun
`npm run db:migrate`; it retries finalization without repeating completed data
work. Existing rows already marked `finishedAt` remain final after upgrading.

After an upgrade that adds competitor organic snapshots, optionally compact the
latest completed SERP for each keyword into the new query-friendly column:

```bash theme={null}
npm run db:backfill:competitor-organics
```

Run the command with `DATABASE_URL` available. It is batched and idempotent,
and leaves checks without a usable historical organic payload unchanged. The
app continues to read those legacy payloads directly, so the backfill does not
need to block the web deployment.

### Restart

After a successful migration, the script starts the selected `app` and
`worker` services from the matched release images. It does not perform the
operator's post-start readiness checks; those are the next step.

### Validate readiness

After the script returns success, confirm the deployment is healthy:

* Call authenticated `GET /api/v1/health` with an API credential or the
  deployment's `INTERNAL_PROBE_TOKEN` Bearer header. Confirm
  `services.migrations` is `ready`; the endpoint returns 503 when a bundled
  Prisma migration has not been applied, an active data migration is
  incomplete, has a checksum mismatch, or cannot be read, or the public ID
  database contract is not ready.

* Sign in and read one project to confirm the app serves authenticated
  requests.

* Check Prisma status in Docker Compose:

  ```bash theme={null}
  docker compose exec app npx prisma migrate status
  ```

* Confirm the web and worker report the same release. For split deployments,
  deploy the web app so migrations apply, then immediately deploy the worker
  from the same release tag. Version skew commonly appears as "The column ...
  does not exist" errors in worker logs or as failing scheduled checks while
  the web app works.

* When scheduled work is enabled, confirm the Temporal worker reports ready
  and its maintenance schedules are created or already exist.

`/api/v1/readiness` is the public traffic-admission (readiness) probe; it does
not replace the authenticated health checks above. Use `/api/v1/liveness` for
restart probes and authenticated `GET /api/v1/health` for the deeper
service/migration contract. See
[Backup and restore](/docs/self-hosting/backup-restore) for its role in restore
validation.

### Failure paths

A failed verification or migration returns nonzero and prevents app/worker
restart. No success is reported. The script does not perform automatic rollback.
Inspect the migration output before retrying or restoring. If a migration left
the database in an intermediate state, a database restore may be required; see
[Restore from backup](#restore-from-backup) below.

### Restore from backup

If the upgrade cannot complete, restore the pre-upgrade database backup with
the matching previous release. Restoring must use the same bisibility release
that created the dump; an image rollback alone does not reverse Prisma
migrations. See [Backup and restore](/docs/self-hosting/backup-restore) for the
full restore procedure, including stopping writers, running migrations after
restore, and readiness validation.

### Legacy upgrades

Older one-time source upgrades have their own pages and are kept for
reference.

<span id="upgrade-from-v010-to-v020" />

## Upgrade from v0.1.0 to v0.2.0

<a id="1-back-up-postgresql" />

<a id="2-check-the-port-change" />

<a id="3-fetch-v020" />

<a id="4-keep-deliberate-host-local-database-access" />

<a id="5-build-and-start-the-release" />

<a id="6-verify-the-upgrade" />

<a id="7-roll-back" />

This one-time source upgrade has its own page:
[Upgrade from v0.1.0 to v0.2.0](/docs/self-hosting/legacy-upgrades/v0-1-to-v0-2).
