Creates durable, resumable workflows using Vercel's Workflow DevKit. Use when building workflows that need to survive restarts, pause for external events, retry on failure, or coordinate multi-step operations over time. Triggers on mentions of "workflow", "durable functions", "resumable", "workflow devkit", or step-based orchestration.
workflow DocumentationYour knowledge of workflow is outdated.
The workflow documentation outlined below matches the installed version of the Workflow DevKit.
Follow these instructions before starting on any workflow-related tasks:
Search the bundled documentation in node_modules/workflow/docs/:
glob "node_modules/workflow/docs/**/*.mdx"grep "your query" node_modules/workflow/docs/Documentation structure in node_modules/workflow/docs/:
getting-started/ - Framework setup (next.mdx, express.mdx, hono.mdx, etc.)foundations/ - Core concepts (workflows-and-steps.mdx, hooks.mdx, streaming.mdx, etc.)api-reference/workflow/ - API docs (sleep.mdx, create-hook.mdx, fatal-error.mdx, etc.)api-reference/workflow-api/ - Client API (start.mdx, get-run.mdx, resume-hook.mdx, etc.)ai/ - AI SDK integration docserrors/ - Error code documentationRelated packages also include bundled docs:
@workflow/ai: node_modules/@workflow/ai/docs/ - DurableAgent and AI integration@workflow/core: node_modules/@workflow/core/docs/ - Core runtime (foundations, how-it-works)@workflow/next: node_modules/@workflow/next/docs/ - Next.js integrationWhen in doubt, update to the latest version of the Workflow DevKit.
Directives:
"use workflow"; // First line - makes async function durable
"use step"; // First line - makes function a cached, retryable unit
Essential imports:
// Workflow primitives
import { sleep, fetch, createHook, createWebhook, getWritable } from "workflow";
import { FatalError, RetryableError } from "workflow";
import { getWorkflowMetadata, getStepMetadata } from "workflow";
// API operations
import { start, getRun, resumeHook, resumeWebhook } from "workflow/api";
// Framework integrations
import { withWorkflow } from "workflow/next";
import { workflow } from "workflow/vite";
import { workflow } from "workflow/astro";
// Or use modules: ["workflow/nitro"] for Nitro/Nuxt
"use workflow" functions run in a sandboxed VM. "use step" functions have full Node.js access. Put your logic in steps and use the workflow function purely for orchestration.
// Steps have full Node.js and npm access
async function fetchUserData(userId: string) {
"use step";
const response = await fetch(`https://api.example.com/users/${userId}`);
return response.json();
}
async function processWithAI(data: any) {
"use step";
// AI SDK works in steps without workarounds
return await generateText({
model: openai("gpt-4"),
prompt: `Process: ${JSON.stringify(data)}`,
});
}
// Workflow orchestrates steps - no sandbox issues
export async function dataProcessingWorkflow(userId: string) {
"use workflow";
const data = await fetchUserData(userId);
const processed = await processWithAI(data);
return { success: true, processed };
}
Benefits: Steps have automatic retry, results are persisted for replay, and no sandbox restrictions.
When you need logic directly in a workflow function (not in a step), these restrictions apply:
| Limitation | Workaround |
|---|---|
No fetch() | import { fetch } from "workflow" then globalThis.fetch = fetch |
No setTimeout/setInterval | Use sleep("5s") from "workflow" |
| No Node.js modules (fs, crypto, etc.) | Move to a step function |
Example - Using fetch in workflow context:
import { fetch } from "workflow";
export async function myWorkflow() {
"use workflow";
globalThis.fetch = fetch; // Required for AI SDK and HTTP libraries
// Now generateText() and other libraries work
}
Note: DurableAgent from @workflow/ai handles the fetch assignment automatically.
Use FatalError for permanent failures (no retry), RetryableError for transient failures:
import { FatalError, RetryableError } from "workflow";
if (res.status >= 400 && res.status < 500) {
throw new FatalError(`Client error: ${res.status}`);
}
if (res.status === 429) {
throw new RetryableError("Rate limited", { retryAfter: "5m" });
}
All data passed to/from workflows and steps must be serializable.
Supported types: string, number, boolean, null, undefined, bigint, plain objects, arrays, Date, RegExp, URL, URLSearchParams, Map, Set, Headers, ArrayBuffer, typed arrays, Request, Response, ReadableStream, WritableStream.
Not supported: Functions, class instances, Symbols, WeakMap/WeakSet. Pass data, not callbacks.
Use getWritable() in step functions to stream data:
async function streamData() {
"use step"; // Required - streaming only works in steps
const writer = getWritable();
await writer.write(data);
writer.releaseLock(); // Always release the lock
}
// Close when done
await getWritable().close();
# Check workflow endpoints are reachable
npx workflow health
npx workflow health --port 3001 # Non-default port
# Visual dashboard for runs
npx workflow web
npx workflow web --app-url http://localhost:3001
# CLI inspection (for agents)
npx workflow inspect runs
npx workflow inspect run <run_id>
Tip: Only import workflow APIs you actually use. Unused imports can cause 500 errors.