Upgrades
The upgrade procedure, migrations with several replicas, rollback, and what each version needs.
The procedure
Read the release notes
Read every release between the version you run and the target, especially their upgrade notes. Some releases have migrations that take time on a large instance, and some cannot be applied as a rolling upgrade.
Back up
PostgreSQL, the file storage, and your secrets (AUTH_SECRET, ENCRYPTION_KEY). See Backups and restore.
Pull the new images
Set both OCI_API_IMAGE and OCI_WEB_IMAGE to the target version and pull them. Always deploy the API and web images as a pair from the same release.
Migrate
With one API replica, leave RUN_MIGRATIONS=true: the API applies migrations on start, under a PostgreSQL advisory lock.
With several replicas, run migrations once before replacing them:
docker compose --profile tools run --rm migrate
RUN_MIGRATIONS=false docker compose up -d --no-buildWith RUN_MIGRATIONS=false, a replica refuses to start unless the latest migration it ships with is recorded.
Verify
Wait for /api/health/ready, then check sign-in, a conversation, web search and a file download, and open System health.
Releases keep the previous minor version working against the new schema where they can, so replicas can usually be replaced one at a time. The per-version notes below say when not.
Rollback
Images can be rolled back by setting OCI_API_IMAGE and OCI_WEB_IMAGE to the previous versions. Migrations are forward-only: if a release's migration is incompatible with the previous version, restore the pre-upgrade database backup and the matching file snapshot before starting the old images. Never rotate ENCRYPTION_KEY as part of a rollback.
Per-version notes
To v0.10.2
No migrations and no new environment variables. Replace the API and web images as a pair, from v0.10.0 or v0.10.1 directly, one replica at a time. Skip v0.10.1: it can create many empty conversations from a single send. See v0.10.2.
To v0.10.1
No migrations and no new environment variables. A web change only: how a reply shows its reasoning and tool steps. Replace the API and web images as a pair, from v0.10.0 directly, one replica at a time. See v0.10.1.
To v0.10.0
Migrations 0035 to 0038. All four are safe to apply before the new images are deployed: none scans or rewrites a large table, and every lock they take is brief. v0.9 replicas keep working against the new schema while you replace them one at a time.
| Migration | What it does |
|---|---|
0035_backup_files | Six nullable columns on backup_run (a small table only the backup job writes) for what each run copied, read back and swept. |
0036_personal_defaults | One nullable column for each person's default reasoning level. |
0037_compaction_failure | A new table for summaries people asked for that failed. |
0038_usage_kept_after_deletion | user_id becomes nullable on usage_event, usage_record and quota_denial, and their keys to accounts set it to null instead of deleting the rows. The new keys are added NOT VALID, so nothing scans or rewrites a table, whatever its size. |
What else changes:
- Backups keep their old behaviour until you choose. An instance that saved backup settings before v0.10 goes on listing files without copying them until an administrator turns on Copy attachment files. The first copy reads and copies every file once, so it takes longer and uses as much storage again as your files do now; later backups copy only new files. The backup credential now also needs
s3:ListBucketon its prefix. See Backups. - Delete own account is off for every role. Nobody can delete their own account until you turn it on for a role on Roles & access.
RATE_LIMIT_AUTH_PER_MINUTEnow applies (it had no effect before): sign-in, sign-up, password reset and verification are limited to 10 a minute per client address and per email by default. SetTRUSTED_PROXIESbehind a proxy (below) before many people share one address. See Sign-in attempts.TRUSTED_PROXIES(from v0.9.2): behind a load balancer, another proxy or an ingress, set it on the web container. See Reverse proxy.- Usage is kept after an account is deleted, without the person, and shown as Deleted accounts. Usage of accounts deleted before the upgrade is already gone.
- The API image is about 10 MB larger: it carries Noto fonts for PDF export in every script.
- New conversations start from each person's saved default model, then the instance's. The model last picked in a browser is no longer remembered there.
No new required environment variables. See v0.10.0.
To v0.9.2
No migrations. A security fix to how client addresses are recorded, and the new optional TRUSTED_PROXIES for the web container. Replace the API and web images as a pair. v0.9.1 has no published images: upgrade from v0.9.0 straight to v0.9.2 or later. See v0.9.2.
To v0.9.1
No migrations and no new environment variables. v0.9.1 was never published as images; its changes are in v0.9.2. See v0.9.1.
To v0.9.0
Migrations 0028 to 0034. Most only create new, empty tables and apply instantly; v0.8 replicas never read them. Two need care:
0034_compliancenumbers every existing audit entry while holding an exclusive lock onaudit_log, so its time (and how long audit writes wait) grows with the size of the audit log. On a very large log, shorten audit retention first or migrate in a quiet period. It also adds an index tomessage, which scans the table once and blocks message writes while it builds.0031_drop_boring_modedrops a column v0.7 still reads. From v0.8, a rolling upgrade is fine. From v0.7 directly, stop the old replicas before migrating rather than replacing them one by one.
Also in v0.9.0: the API image includes the PostgreSQL 17 client tools; file exports need up to two CPU cores and about 1.2 GB extra memory per API replica at peak; artifacts need the artifact frame headers if you run your own proxy; backups, compliance export, webhooks, connectors and reranking need outbound access to their endpoints. Meaning-based search needs pgvector (below). See v0.9.0.
To v0.8.0
Migrations 0026 and 0027 only create new tables and apply instantly. Project files uploaded earlier are split into searchable passages afterwards by a background job, 50 files every five minutes; until then they are used whole. Connector OAuth needs APP_URL to be the address people use. See v0.8.0.
To v0.7.0
Migrations 0022 to 0025. 0023_message_text_search builds a full-text index over every message, inside the migration's transaction: on a large message table it takes time and blocks writes to message until it finishes (reads continue). Allow for it in your maintenance window and in any start-up timeout, and check free disk space first. To avoid the write block, build the index beforehand from a direct connection:
CREATE INDEX CONCURRENTLY IF NOT EXISTS "message_text_search_idx" ON "message"
USING gin (to_tsvector('simple'::regconfig, jsonb_path_query_array("parts", '$[*] ? (@.type == "text").text'::jsonpath)));The migration then finds it and does nothing. If a concurrent build fails, drop the INVALID index (DROP INDEX CONCURRENTLY message_text_search_idx;) and try again. See v0.7.0.
To v0.5.0
Migrations 0020 and 0021 are required, and old API replicas must be drained and stopped before migrating: older versions do not honour the new upload reservations or the new reply admission. Do not run old and new API versions together. See Earlier releases.
pgvector for meaning-based search
Meaning-based search needs the pgvector extension. OCI never creates it. If your PostgreSQL has the package (managed services usually offer it; the pgvector/pgvector:pg17 image includes it), enable it once as a superuser or the role allowed to create extensions:
docker compose exec -T postgres psql --username=oci --dbname=oci \
-c 'CREATE EXTENSION IF NOT EXISTS vector;'The bundled Compose stack uses postgres:17-alpine, which does not include pgvector. Two ways to get it:
The data directory stays as it is; no dump and restore.
FROM postgres:17-alpine
ARG PGVECTOR_VERSION=0.8.6
RUN apk add --no-cache --virtual .build-deps build-base git \
&& git clone --depth 1 --branch "v${PGVECTOR_VERSION}" \
https://github.com/pgvector/pgvector.git /tmp/pgvector \
&& cd /tmp/pgvector \
&& make OPTFLAGS="" with_llvm=no \
&& make install with_llvm=no \
&& cd / && rm -rf /tmp/pgvector \
&& apk del .build-depsBuild it, point the postgres service at it, recreate the container on the same volume, and run the CREATE EXTENSION command above.
OCI compares vectors with an exact scan of one project's passages; no vector index is needed.