- Storage, Config & Secrets
- Artifact overflow to blob storage (SeaweedFS / S3)
Artifact overflow to blob storage (SeaweedFS / S3)
When a step or run returns a large output — or an entity stream writes a large snapshot — Ironflow can transparently move that payload out of the database and into a blob backend, leaving only a small reference behind. Your functions never see the difference — reads inflate the payload back automatically.
This guide shows how to enable overflow and point it at a self-hosted SeaweedFS S3 endpoint (or any S3-compatible backend).
How it works
large value blob backend ─────────── ──────────── > threshold ──offload──▶ {"__blob__":true,...} ──▶ artifacts/{env}/{run}/{step}/v{ver}/output-{hash} (steps) runs/{env}/{run}/v{ver}/output-{hash} (run outputs) snapshots/{env}/{type}/{id}/v{ver}/state-{hash} (entity-stream snapshots) ≤ threshold ──inline──▶ stored in the DB column any read ◀──inflate── full bytes restored before your function sees it- Threshold-gated. Only outputs larger than the configured threshold offload. Everything else stays inline in the database.
- Transparent. Functions, the dashboard,
ironflow inspect, and event subscribers all receive the full output — the reference is resolved server-side. - Reads always inflate. Disabling offload later (threshold
0) does not break reads of outputs that were offloaded while it was on.
Single-node default: local filesystem
On a single node, overflow needs no backend configuration. Blobs are written to
a blobs/ directory next to the SQLite database (the data directory). Overflow
is still off until you set a threshold — see Enable
overflow.
The local filesystem backend is for single-node deployments only: the files live on one node’s disk and are invisible to other nodes. A multi-node cluster must use a shared S3 backend (Ironflow refuses to start a cluster on the filesystem backend).
Enable overflow
Set a threshold. Outputs larger than it offload; the value accepts
human-readable sizes (1MB, 512KiB, 4MB).
spec: blobs: artifactThreshold: "1MB" # offload outputs larger than 1 MBOr via environment variable:
IRONFLOW_ARTIFACT_THRESHOLD=1MB ./ironflow serveAn empty value or 0 disables offload (the default). The read/inflate path is
always active regardless.
Point overflow at SeaweedFS
SeaweedFS exposes an S3-compatible API and is the recommended self-hosted backend.
1. Run SeaweedFS with the S3 gateway
# Single-binary dev/self-host: filer + volume + S3 API on :8333weed server -dir=/data/seaweedfs -s3 -s3.config=/etc/seaweedfs/s3.jsonDefine an access key/secret and a bucket in the S3 config:
{ "identities": [ { "name": "ironflow", "credentials": [ { "accessKey": "ironflow", "secretKey": "REPLACE_WITH_A_SECRET" } ], "actions": ["Read:ironflow-artifacts", "Write:ironflow-artifacts", "List:ironflow-artifacts"] } ]}Create the bucket once it is running:
weed shell <<< "s3.bucket.create -name ironflow-artifacts"2. Provide credentials to Ironflow
The S3 driver reads credentials from the standard AWS environment variables:
export AWS_ACCESS_KEY_ID=ironflowexport AWS_SECRET_ACCESS_KEY=REPLACE_WITH_A_SECRET# AWS_SESSION_TOKEN is also honored if your backend issues temporary credsNever put credentials in blobs.url or commit them — they belong only in the
environment (or your secret manager).
3. Point Ironflow at the endpoint
The blob URL is s3://{bucket}?endpoint={url}. The endpoint scheme selects TLS:
https:// connects securely, http:// does not. region is optional.
spec: blobs: url: "s3://ironflow-artifacts?endpoint=https://seaweedfs.internal:8333" artifactThreshold: "1MB"Or via environment:
export IRONFLOW_BLOB_URL="s3://ironflow-artifacts?endpoint=https://seaweedfs.internal:8333"export IRONFLOW_ARTIFACT_THRESHOLD=1MB./ironflow serveSeaweedFS uses path-style addressing, which the driver detects automatically for non-AWS endpoints — no extra configuration needed.
Using AWS S3 or another provider instead
The same s3://bucket?endpoint=... URL works for any S3-compatible backend
(AWS S3, MinIO, Cloudflare R2, Backblaze B2). Set endpoint to the provider’s
S3 endpoint and supply the matching AWS_* credentials.
Configuration reference
YAML (spec.blobs) | Environment variable | Default | Meaning |
|---|---|---|---|
url | IRONFLOW_BLOB_URL | (empty → local filesystem) | s3://bucket?endpoint=...®ion=... selects the S3 backend |
artifactThreshold | IRONFLOW_ARTIFACT_THRESHOLD | (empty → off) | Size above which outputs offload (1MB, 512KiB, …) |
Environment variables override the YAML values.
Operational notes
- Multi-node requires S3. A cluster (external NATS) refuses to start on the
filesystem backend — set an
s3://URL. Reads of previously-offloaded outputs need the shared backend too, so the requirement holds even with offload off. - Deleting an environment reclaims its blobs eagerly. Ironflow sweeps all offloaded blobs for that environment from the blob backend after the database rows are removed. Deleting a project or an organization sweeps the environments underneath it too, but only where the delete itself succeeds: an environment that still holds functions blocks the cascade with a foreign key error, so empty the environment first. The sweep runs detached from the request’s cancellation, so a client disconnect mid-delete does not strand the blobs — though the delete call itself does not return until the sweep finishes, so a very large delete can take a while to respond. Blobs for runs and steps inside a live environment still accumulate — there is no per-run or per-step garbage collection. Manage lifecycle for long-running environments yourself (for S3, a bucket lifecycle policy).
- Missing blobs surface explicitly. If an offloaded blob is gone from the
backend, the read fails with an explicit “output unavailable” state (a
non-retryable
DataLoss), naming the missing key — never a silent or opaque error. - Metrics. When metrics are enabled, overflow records offloads, bytes offloaded, degrades (offload failed → written inline), backend errors, and unavailable (missing-blob) events. See Observability.