--- title: 'Overview' description: 'A plain async function marked "use workflow" that orchestrates idempotent steps and survives crashes, redeploys, and long waits.' position: 1 --- # Workflows > A workflow is a plain async function marked `'use workflow'` that orchestrates > `'use step'` units. Each step runs once, persists its result, and retries on > failure. The whole run survives crashes and redeploys, so it can pause for minutes, > days, or months and resume where it stopped. An [agent](/docs/sdk/agents/overview) holds an open-ended conversation. A workflow runs a fixed, auditable pipeline: validate, call a model, write a side effect. Stackbone takes the durability from the upstream [Workflow SDK](https://workflow-sdk.dev/docs) (the same engine behind [Vercel Workflows](https://vercel.com/docs/workflows)) and runs it on a per-install Redis-backed runtime. ## The execution model - Two directives do the work. `'use workflow'` on the function makes it durable and replayable. `'use step'` on a sub-function makes that unit run once, persist its result, and retry on failure. Every side effect belongs in a step. - The body must be deterministic, because the runtime replays it on every crash-resume. Keep it free of clocks, randomness, and direct I/O. Steps hold the real work, and the runtime replays their recorded results instead of re-running them. - Only a step may touch the platform client. The body runs in an isolated sandbox with no Node.js access, so reference `stackbone.*` only inside a `'use step'` function. One `stackbone.*` reference in the body, or in a helper the body calls, fails every workflow in the workspace at run time. - Sibling `inputSchema` and `outputSchema` Zod exports are the workflow's typed contract. The runtime validates the input before a run starts. - Discovery is by convention. The runtime picks up any `workflows/.workflow.ts`, and the exported function is the camelCase name plus `Workflow`. - One step has a time ceiling. It runs inside a single delivery to the runtime, capped at 15 minutes by default. The runtime abandons a step that runs past the ceiling and does **not** retry it. The abandoned copy may still be running, and a retry would start a second one beside it. Raise `WORKFLOW_HTTP_TIMEOUT_MS` on the deployment when a step needs longer, such as one long model call over a large input. ```ts // workflows/qualify-lead.workflow.ts import { z } from '@stackbone/sdk'; export const inputSchema = z.object({ email: z.email(), company: z.string() }); export const outputSchema = z.object({ score: z.number(), qualified: z.boolean() }); export async function qualifyLeadWorkflow(input: z.infer) { 'use workflow'; const score = await scoreLead(input.company); // a durable step return { score, qualified: score >= 60 }; } async function scoreLead(company: string) { 'use step'; return company.length * 5; } ``` Kill the runtime mid-run and it resumes from the last completed step instead of replaying everything. ## Where to go next - **[Getting started](/docs/sdk/workflows/building-workflows)**: scaffold, trigger, and observe your first workflow, including long waits and approvals. - **[Examples](/docs/examples/workflows/onboarding-pipeline)**: an onboarding pipeline, a refund with a human approval, and a scheduled digest. - **[Serial execution](/docs/sdk/workflows/serial-execution)**: make a workflow run one at a time, in arrival order, when two copies must never overlap. - **[Workflow agents](/docs/sdk/workflow-agents/overview)**: let a step delegate to an agent. - **[Human-in-the-loop](/docs/sdk/humans/approval)**: pause a run for a person to approve.