Overview
Self-hosted Onyx bundles an S3-compatible store for the files it keeps outside PostgreSQL. Until now that store was MinIO. MinIO archived its community edition and removed its public images, so Onyx is replacing it with SeaweedFS, running as a service called the object store. The upgrade moves your existing files across automatically, with no downtime and a safe rollback. Installs that already use external storage (AWS S3, Google Cloud Storage, Azure Blob Storage, or another S3-compatible service) are not affected, and neither is Onyx Cloud.What the object store holds
The object store holds the only copy of every file body Onyx keeps. PostgreSQL holds the pointers to those files and OpenSearch holds the search index, but the bytes themselves live only here:- Files attached to chats and images generated in chats
- Files uploaded to projects and the user library
- Documents uploaded through the File connector
- Craft sandbox snapshots and coding history
- Enterprise branding assets such as the logo
- Images and attachments extracted from connector documents during indexing
- Indexing checkpoints, generated reports, and query history and log exports
Migration
The object store ships in Onyxv5.0.0 (Helm chart 0.9.0), a major version bump.
That release runs both stores side by side during a transition:
- The app writes and deletes every file in both the object store and MinIO, so a rollback still finds it.
- A read that misses the object store falls back to MinIO.
- A copy job moves every file that Onyx tracks from MinIO into the object store. It never replaces a file the app wrote, except when an older release wrote a newer version after a rollback, and it skips objects no file record points at.
Docker Compose
Theobject-store service runs SeaweedFS on its own object_store_data volume,
and the object-store-copy service runs the copy. Upgrades through the Onyx CLI
switch the app to the object store and keep MinIO as the fallback on their own.
Watch the copy with:
Legacy MinIO copy complete.
It finishes only after a pass copies nothing and LEGACY_COPY_SETTLE_SECONDS (600 by default)
have passed since it started. If objects fail to copy, it logs the keys and retries every five minutes.
The app keeps serving from both stores in the meantime.
If you upgrade a hand-maintained
.env yourself, the app stays on MinIO until you change two settings:
set S3_ENDPOINT_URL=http://object-store:8333 and uncomment S3_LEGACY_ENDPOINT_URL=http://minio:9000.
The same applies when the CLI upgrades an install whose .env reaches the bundled MinIO under any address other than
http://minio:9000: the CLI leaves that endpoint alone, so make the two changes yourself,
with S3_LEGACY_ENDPOINT_URL set to the address your .env used. Nothing breaks before you do,
and the copy starts once you restart with those values.Helm
Chart0.9.0 adds the objectStore section
and the <fullname>-legacy-minio-copy-<hash> Job,
where <fullname> is the release name when it contains onyx and <release>-onyx otherwise.
The MinIO subchart only gains a keep annotation on its PVC, so its pod does not restart.
Watch the copy with:
helm upgrade returns without waiting for it. --reuse-values,
ArgoCD, Flux and rendered manifests all work. If the Job fails, fix the cause, delete it, and upgrade again to rerun it.
A rerun skips every object already copied.
Before upgrading, check that the new <fullname>-object-store PVC can hold all of MinIO’s data.
It takes the size and storage class of minio.persistence unless you set objectStore.persistence.
The chart’s MIGRATION.md covers air-gapped registries, pod security, and OpenShift.
How long it takes
The copy runs at a couple of hundred files per second, or about 165 MB/s when the files are large. It reports completion only after a verification pass finds nothing new to copy and ten minutes have passed since it started. The pass takes about 20 minutes per million files. Measured on a replica of a real install and on a synthetic million-file store:
Both stores hold every file until you retire MinIO. See sizing.
The copy is safe to interrupt. If the copier, MinIO, the object store or PostgreSQL goes down mid-copy,
the copy stops within about a minute and the next run picks up where it left off. Nothing is lost,
because the app keeps writing to both stores and reading from either.
Rollback
Rolling back to the previous release points the app back at MinIO. MinIO has every file, including files uploaded after the upgrade, because the transition release writes to both stores. The object store volume stays, and the next upgrade continues the copy. The Onyx CLI and Helm switch the endpoint back for you. On a hand-maintained.env,
set S3_ENDPOINT_URL=http://minio:9000 again and clear S3_LEGACY_ENDPOINT_URL before you start the older release.
One exception: a file written while MinIO was unavailable reaches MinIO only once the failed write is replayed.
In Compose the copy service replays it within five minutes of MinIO answering again.
In Helm the replay happens at the next copy run, so if MinIO had an outage after the Job completed,
delete the Job and upgrade again before you roll back, and wait for it to complete.
Retiring MinIO
Once the copy has completed, you can stop MinIO without waiting for a later release. After this, a rollback to a release before the object store no longer sees files uploaded since.1
Run the retire command
In Compose:In Helm, from an API server pod:It copies anything left, waits a quiet minute, and checks that nothing reached MinIO alone in that time.
If something did, a container or pod on the older release is still running, so it refuses and MinIO stays in use.
Otherwise it writes a marker to the object store, and within a minute every running process stops writing to MinIO.
No restart is needed.
2
Stop MinIO
In Compose, set Then set
MINIO_REPLICAS=0 in .env and run docker compose up -d minio.
The minio_data volume stays until you remove it.In Helm, first make sure the MinIO PVC carries the keep annotation,
since an upgrade with --reuse-values can miss the one the chart adds:minio.enabled: false and objectStore.enabled: true and upgrade.
The MinIO PVC stays until you delete it.