Upgrading
An upgrade is four steps, and skipping the third is the one that produces a deployment that looks fine and is subtly broken.
-
Read the changelog. The changelog is kept per release; every entry that needs an operator action says so. Releases are also on GitHub.
-
Move to the new version. Change the pinned image tag, or pull the new git tag and rebuild:
Terminal window git fetch --tagsgit checkout v<version>bun installbun run buildThe published tags are listed on the GitHub releases page and on the container package page.
-
Re-run the provisioning step against the same database:
Terminal window bun run db:setup -
Restart the server.
Why step 3 is not optional
Section titled “Why step 3 is not optional”db:setup is the only thing that applies a release’s structural changes, and it is idempotent — it
upserts, so running it against an already-current database changes nothing. What a release can add:
- New collections, for a capability that did not exist before.
- New indexes — including TTL indexes. A collection that MongoDB auto-creates on first write has no TTL index, so documents that were meant to expire simply do not, and nothing complains. It also drops stale expiry indexes that a release has stopped writing the field for.
- Seed changes. When a release changes the admin seed — a new reserved client, a new field on
the administrator bucket, a group the ownership model now expects —
db:setupis what applies it. The reservedadmin-mcpagent client arrived exactly this way, and the script carries an explicit$addToSetfor it because$setOnInsertwould not touch a project that already existed.
db:setup exits non-zero when a constraint it declares is not in force, so make it a gate rather
than a fire-and-forget: the shipped fly.toml runs it as release_command and Fly aborts the deploy
on failure; the Compose files run it as a setup service the server depends_on with
service_completed_successfully; on Kubernetes it is a Job you wait for.
What a restart carries, and what it does not
Section titled “What a restart carries, and what it does not”- Server settings are boot-only. Everything on
ApplicationConfig— every feature flag, every rate-limit number — is read from the config store and applied at module load. A change you made in the console last week takes effect at this restart, which makes an upgrade a good moment to re-read the settings reference for anything the release added. The console says as much when you save. - Signing keys persist in the database, through the
jwksStoreadapter, and are loaded once at startup. An upgrade neither rotates nor invalidates them: tokens issued before it still verify, and/jwksserves the same key set. Keys are not environment configuration and there is nothing to carry across by hand. - SMTP settings are the exception to boot-only: they are read live from the settings store, so they apply without a restart.
- Tokens, sessions and grants survive, since they live in MongoDB. Users are not signed out by an upgrade.
After the restart
Section titled “After the restart”curl -sf https://auth.example.com/healthcurl -s https://auth.example.com/.well-known/openid-configuration | jq -r .issuerThe second is the check worth automating — the shipped deploy workflow does exactly this, because the advertised issuer is the one value a deploy can get wrong in a way nothing else catches.
Then open /admin and sign in. That single act exercises the seed, the console client, the
administrator bucket and the authorization code flow at once, so if it works, the upgrade landed.
Super administrators should also glance at Faults: only genuine defects are recorded there —
routine client rejections never are — so anything new after an upgrade is worth reading.