Skip to content

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).

ironflow.yaml
spec:
blobs:
artifactThreshold: "1MB" # offload outputs larger than 1 MB

Or via environment variable:

Terminal window
IRONFLOW_ARTIFACT_THRESHOLD=1MB ./ironflow serve

An 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

Terminal window
# Single-binary dev/self-host: filer + volume + S3 API on :8333
weed server -dir=/data/seaweedfs -s3 -s3.config=/etc/seaweedfs/s3.json

Define an access key/secret and a bucket in the S3 config:

/etc/seaweedfs/s3.json
{
"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:

Terminal window
weed shell <<< "s3.bucket.create -name ironflow-artifacts"

2. Provide credentials to Ironflow

The S3 driver reads credentials from the standard AWS environment variables:

Terminal window
export AWS_ACCESS_KEY_ID=ironflow
export AWS_SECRET_ACCESS_KEY=REPLACE_WITH_A_SECRET
# AWS_SESSION_TOKEN is also honored if your backend issues temporary creds

Never 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.

ironflow.yaml
spec:
blobs:
url: "s3://ironflow-artifacts?endpoint=https://seaweedfs.internal:8333"
artifactThreshold: "1MB"

Or via environment:

Terminal window
export IRONFLOW_BLOB_URL="s3://ironflow-artifacts?endpoint=https://seaweedfs.internal:8333"
export IRONFLOW_ARTIFACT_THRESHOLD=1MB
./ironflow serve

SeaweedFS 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 variableDefaultMeaning
urlIRONFLOW_BLOB_URL(empty → local filesystem)s3://bucket?endpoint=...&region=... selects the S3 backend
artifactThresholdIRONFLOW_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.