Serverless pipelines, cron jobs, and background work
Run cron jobs, webhook-triggered workflows, and multi-step background jobs as serverless pipelines — staged work, retries, and fan-out built on the same functions that serve your live HTTP API.
Related guides and docs
Get started free →How it works
How serverless pipelines work
Define steps
Pick existing functions as pipeline steps, then wire up their inputs, outputs, and the dependencies between them.
Connect and schedule
Link steps into a DAG or a sequential chain, then add cron triggers or webhook listeners so runs start automatically.
Monitor in real time
Watch each step's status, logs, and output live, and replay a failed step without re-running the whole pipeline.
Features
Built for real workflows
DAG execution
Steps run in parallel whenever their dependencies allow, with full dependency resolution handled out of the box.
Webhook triggers
Trigger a pipeline from the API or the UI and pass a structured payload straight into the first step.
Manual approval
Pause execution at any step and require a human sign-off before the pipeline proceeds.
Cron scheduling
Schedule pipelines with a plain cron expression — daily reports, batch jobs, cleanup tasks.
Pipelines reuse the same functions you expose through the gateway.
Decision guide
Pipelines vs direct functions vs async jobs
Use pipelines
Reach for pipelines when cron jobs, webhook-triggered workflows, or background jobs need retries, branching, fan-out, or staged orchestration across several functions.
Use direct functions
Stick with a direct function when a single HTTP request can finish quickly in one gateway handler — no cron, no webhooks, no multi-step state.
Use async jobs
Use async jobs when callers should return immediately and all you need is a queued background job, not a full DAG across many steps.
Example
DAG pipeline (manual trigger)
{ "schemaVersion": 1, "nodes": [ { "id": "t1", "kind": "manualTrigger", "name": "Start", "position": { "x": 0, "y": 0 }, "config": {} }, { "id": "n1", "kind": "lambda", "name": "Classify intent", "position": { "x": 240, "y": 0 }, "config": { "functionId": "intent-classifier", "onError": "failPipeline" } }, { "id": "n2", "kind": "lambda", "name": "Billing agent", "position": { "x": 480, "y": 0 }, "config": { "functionId": "billing-agent", "onError": "failPipeline" } }, { "id": "r1", "kind": "respond", "name": "Done", "position": { "x": 720, "y": 0 }, "config": { "statusCode": 200, "bodyMapping": { "ok": true } } } ], "edges": [ { "id": "e1", "sourceNodeId": "t1", "targetNodeId": "n1" }, { "id": "e2", "sourceNodeId": "n1", "targetNodeId": "n2", "sourceHandle": "success" }, { "id": "e3", "sourceNodeId": "n2", "targetNodeId": "r1", "sourceHandle": "success" } ] }
Sequential example (nightly processing)
{ "schemaVersion": 1, "nodes": [ { "id": "cron", "kind": "cronTrigger", "name": "Nightly 02:00", "position": { "x": 0, "y": 0 }, "config": { "cron": "0 2 * * *", "timezone": "UTC" } }, { "id": "extract", "kind": "lambda", "name": "Extract", "position": { "x": 240, "y": 0 }, "config": { "functionId": "nightly-extract", "onError": "failPipeline" } }, { "id": "transform", "kind": "lambda", "name": "Transform", "position": { "x": 480, "y": 0 }, "config": { "functionId": "nightly-transform", "onError": "failPipeline" } }, { "id": "publish", "kind": "lambda", "name": "Publish", "position": { "x": 720, "y": 0 }, "config": { "functionId": "nightly-publish", "onError": "failPipeline" } } ], "edges": [ { "id": "e1", "sourceNodeId": "cron", "targetNodeId": "extract", "sourceHandle": "default" }, { "id": "e2", "sourceNodeId": "extract", "targetNodeId": "transform", "sourceHandle": "success" }, { "id": "e3", "sourceNodeId": "transform", "targetNodeId": "publish", "sourceHandle": "success" } ] }