Artifact overflow to blob storage (SeaweedFS / S3)
When a step or run returns a large output, 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
step/run output blob backend ─────────────── ──────────── > threshold ──offload──▶ {"__blob__":true,...} ──▶ artifacts/{env}/{run}/{step}/v{ver}/output-{hash} ≤ 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. - Environment delete reclaims blobs eagerly. When you delete an environment, Ironflow sweeps all offloaded blobs for that environment from the blob backend after the database rows are removed. 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.