Storage Configuration
Configure your organization's object storage — local, S3-compatible, or Azure Blob — and understand when files upload directly from the browser versus through the server.
Every organization stores its files (knowledge-base documents, chat attachments, avatars, workflow artifacts) in a storage backend you configure under Settings → Organization → Storage. Three providers are supported:
| Provider | When to use |
|---|---|
| Local | Single-node evaluation installs. Files live on the server's disk. |
| S3-compatible | AWS S3, MinIO, SeaweedFS (bundled), Cloudflare R2, or any S3 API. |
| Azure Blob Storage | Azure-native deployments (the default on Azure Marketplace installs). |
S3 settings
- Endpoint URL — the S3 endpoint the platform servers use. For the bundled SeaweedFS this is the in-cluster service address; for AWS S3 leave it blank.
- Public endpoint URL (optional) — a browser-reachable endpoint used only for signing direct-upload/download URLs. Set this when your Endpoint URL is private (cluster-internal or behind a firewall) but you have exposed the same store publicly (e.g. through an ingress) and want browser-direct transfers.
- Bucket, Region, Access key / Secret key, Force path style — standard S3 client settings. Credentials are stored encrypted in the platform secret store.
Direct uploads vs. server-proxied uploads
For speed, the platform prefers browser-direct transfers: the browser uploads straight to your storage using a short-lived presigned URL. That only works when the storage endpoint is reachable from your users' browsers.
The platform decides automatically:
- AWS S3 / Azure Blob — always direct.
- S3-compatible store with a public hostname — direct.
- S3-compatible store with a private endpoint (the bundled SeaweedFS, or MinIO on a private network) — uploads and downloads are routed through the platform server instead. Everything still works; large transfers simply pass through the server.
- Private endpoint + Public endpoint URL configured — direct, using the public endpoint for signing.
If you configure a Public endpoint URL, the storage host must allow
cross-origin (CORS) PUT/GET requests from your platform origin —
browser-direct transfers are cross-origin requests.
Symptom to watch for: uploads failing in the browser console with
net::ERR_NAME_NOT_RESOLVED against your storage hostname means a private
endpoint leaked into browser transfers. On current versions this cannot
happen — the platform detects private endpoints and proxies automatically.
If you see it, upgrade, or clear the Public endpoint URL field if it
points at a host your users cannot reach.
Changing providers
Switching providers (or buckets) opens a migration dialog that copies existing objects to the new target before the configuration is saved. Configuration changes take effect within five minutes (config caches).
What happens to Analytics (lakehouse) data
Analytics managed tables are stored in Iceberg format inside a per-org Lakekeeper warehouse. File-storage objects (knowledge-base documents, attachments, etc.) and Iceberg data are separate and require separate migration steps.
When you have one or more managed tables, the migration dialog shows an additional Lakehouse cutover section that describes:
- The number of live managed tables that will be copied.
- That Iceberg snapshot history is not preserved — the cutover copies the current table state to the new provider. If you need to preserve time-travel history, contact your administrator before proceeding.
The migration orchestrator copies file objects first, then copies Iceberg tables,
and only flips the storage configuration after both succeed. You can monitor
Iceberg copy progress in the Lakehouse status card on the storage settings
page (copied / total tables with any per-table failures listed).
Lakehouse writes are frozen during the cutover
While the Iceberg copy is in progress, writes to managed tables return an error
(iceberg_cutover_in_progress). Data sources and workflows that write to
Analytics tables will automatically retry on their next tick; no data is lost.
Reads (queries, previews) are not affected — the old warehouse stays available
until the copy completes.
Skipping the lakehouse cutover
The dialog offers a Skip lakehouse cutover option. If you skip, the
configuration is flipped without copying Iceberg data. Lakehouse writes will
be blocked (error iceberg_warehouse_drift) until the cutover is run
separately from the Lakehouse status card.
Use Skip only when you have already migrated Iceberg data out-of-band (contact your Scrydon administrator).
Lakehouse drift banner
If the storage provider was changed previously without completing the Iceberg cutover, the Settings → Storage page shows a warning banner:
Lakehouse drift detected — managed tables are on [old provider] but your storage config points at [new provider].
Click "Run lakehouse cutover" to start the in-product repair. The operation is safe to re-run if it fails partway through — the source data is never modified until the copy completes.
Switching to Local storage while lakehouse data exists
The Local provider cannot host a lakehouse. If you switch to Local while managed tables exist, the page shows a red "Lakehouse needs object storage" banner and lakehouse writes are blocked so no new data lands on the abandoned provider. There is no cutover button in this state — local storage is not a valid cutover destination. To repair, either restore the previous object-storage provider, or configure a new one and run the lakehouse cutover from there.
Error codes you may observe
| Code | HTTP | Meaning |
|---|---|---|
iceberg_warehouse_drift | 409 | Write blocked — storage config changed without completing the Iceberg cutover. Open Settings → Storage and run the lakehouse cutover. |
iceberg_cutover_in_progress | 409 | A lakehouse cutover is running. Writes will resume automatically when it completes (typically a few minutes). |
iceberg_target_missing | 409 | A table's Iceberg tabular was not found — the row will self-heal on the next data-source sync. |
table_not_available | 410 | The table's lifecycle is retired (deleted/archived/failed). |
table_provisioning | 409 | The table is still being provisioned. Retry in a moment. |