Skip to main content
An upgrade has two parts: new code, and any new database migrations.

Update

From the repo root on your server:
update.sh pulls the latest code on your current branch (git pull --ff-only), writes the commit to APP_COMMIT in nous.env, then rebuilds and restarts the containers with docker compose --env-file nous.env up -d --build. The frontend is rebuilt too, because Vite bakes the env into the bundle at build time.

Database migrations

Bundled stack

Nothing to do. The db-schema service runs on every up, so during ./update.sh, and applies the files in supabase/migrations/ this database does not have yet, each in its own transaction. What a database has is recorded in selfhost.schema_migrations. See what ran:
A migration that fails stops db-schema, and the API does not start until it passes, so the app never runs against a half-migrated database. Fix the cause and run docker compose --env-file nous.env up -d again. Do not run migration files by hand on the bundled stack. Some older ones target an earlier schema and would undo later changes. The ledger is by filename, so a file edited after it ran is never run again.

Bring your own Supabase

Migrations are not applied for you. New ones land in supabase/migrations/. To list the ones added between your old and new version:
Run each new file in your Supabase SQL Editor, oldest first. They are written to be idempotent, so running one that is already applied is safe.
Skipping a migration makes the new code fail against the old schema. Apply migrations before or right after the new containers start.
A fresh install never runs migrations. It runs supabase/schema.sql once, which already contains them.

Check the upgrade

/readyz returns 503 when the API cannot reach the database. Then look at the logs: