Skip to content

Asset Lifecycle

Fabric is a stateless execution engine. Workflow-generated assets (videos, images, audio files) are held in temporary storage for a configurable window — 72 hours by default — then automatically deleted. Consumers are responsible for downloading and persisting any assets they need before the window closes.

Fabric distinguishes two categories of assets:

KindExamplesExpiresDefault TTL
GeneratedRendered videos, composed images, TTS audio, transcriptsYes72 hours
PermanentOrg-level assets, voice clones, user uploadsNo (expires_at = NULL)Never

Only generated assets — those produced by workflow runs — participate in the transient lifecycle described below. Permanent assets are unaffected by the reaper.

Workflow run Consumer Reaper
│ │ │
│ 1. Node produces │ │
│ artifact │ │
│ │ │ │
│ 2. SDK uploads blob │ │
│ with TTL ──────────► │ │
│ (expires_at = │ │
│ now + 72h) │ │
│ │ │ │
│ 3. Run completes ──────►│ │
│ (webhook / SSE) │ │
│ │ 4. GET download_url │
│ │ (signed, 1h TTL) │
│ │ │ │
│ │ 5. Download blob │
│ │ & persist locally │
│ │ │
│ │ ┌────────────┤
│ │ │ 6. Poll │
│ │ │ every 5min │
│ │ │ expired? │
│ │ │ │ │
│ │ │ 7. Delete │
│ │ │ blob + │
│ │ │ soft-delete│
│ │ │ row │
│ │ └────────────┘
  1. A workflow node produces an output artifact (video file, image, etc.)
  2. The Python SDK uploads the blob to the object store with a ttl_seconds parameter. The API sets expires_at = now + TTL on the asset row.
  3. The run completes and Fabric emits workflow.run.completed via SSE and webhooks. The event payload includes an output_url pointing to the run’s output endpoint.
  4. The consumer GETs output_url to retrieve artifacts with signed download URLs (or uses the SDK convenience methods).
  5. The consumer downloads the blob and stores it in their own system.
  6. The reaper background task polls for expired assets every 5 minutes.
  7. Expired assets are deleted from the object store and soft-deleted in the database.

Download URLs are signed and short-lived — separate from the 72-hour storage TTL. A signed URL authorizes a single download window; the underlying blob remains available for the full storage TTL.

PropertyDefaultRangeDescription
Signed URL TTL1 hour1 second – 24 hoursHow long the download link is valid
Storage TTL72 hours0 (never) – unlimitedHow long the blob exists in the object store

Request a longer download window with the expires_in query parameter:

// Submit + wait + get output with signed URLs in one call
const result = await fabric.workflows.runs.submitAndGetOutput("video/ai-shorts", {
input: { topic: "AI news" },
expiresIn: 86400, // 24-hour download URLs
});
for (const a of result.artifacts) {
console.log(a.filename, "", a.download_url);
}
// Or download all artifact binaries directly
const files = await fabric.workflows.runs.downloadAllArtifacts(runId);
for (const f of files) {
fs.writeFileSync(f.filename, Buffer.from(f.data));
}
// Or get output for an existing run
const output = await fabric.workflows.runs.getOutput(runId, {
expiresIn: 86400,
});

The response includes both the URL and its expiration timestamp:

{
"download_url": "https://...",
"download_url_expires_at": "2026-04-23T12:00:00Z"
}

A background task runs inside the Fabric server process and automatically cleans up expired assets:

  • Poll interval: every 5 minutes (configurable)
  • Batch size: 100 assets per tick
  • Process per asset:
    1. Delete the blob from the object store (S3 / GCS / local filesystem)
    2. Soft-delete the metadata row (deleted_at = now())
    3. Remove dangling gallery references
  • Failure handling: if blob deletion fails, the row is left intact and retried on the next tick

The reaper uses FOR UPDATE SKIP LOCKED to avoid contention with concurrent workers.

Environment VariableDefaultDescription
ASSET_TTL_HOURS72Storage TTL for generated assets. Set to 0 to disable expiration.
ASSET_REAPER_POLL_SECS300How often the reaper checks for expired assets (seconds)
  1. Download on completion. Wire a webhook to workflow.run.completed and download artifacts immediately. Don’t rely on polling days later.
  2. Use webhooks for automation. For backend pipelines, webhooks are more reliable than polling — they fire as soon as the run finishes and retry on failure.
  3. Request longer signed URLs when needed. If your consumer needs more than 1 hour to download (large files, slow connections), pass expires_in up to 86400 (24 hours).
  4. Don’t treat Fabric as permanent storage. Fabric is a processing engine, not a CDN. Persist assets in your own object store (S3, GCS, etc.) after download.
  5. Monitor reaper health. If expired assets accumulate, check that the Fabric server process is running and the reaper is not failing. Blob deletion errors are retried automatically.