Install & Compatibility
Where this runs
tested against v? · npm install
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
muslnode 18–226 runs
build_error
glibcnode 18–226 runs
build_error
Code
Verified usage
Verified import paths — ran on the pinned version, not inferred.
start
✓ import { start } from 'workflow/api';
✗ import { start } from 'workflow';
The `start` function is used to initiate a workflow run and is imported from the specific 'workflow/api' submodule.
sleep
✓ import { sleep } from 'workflow';
✗ import { sleep } from 'workflow/api';
The `sleep` function allows a workflow to pause for a specified duration without consuming compute resources, maintaining its state durably.
Workflow Function
✓ export async function myWorkflow() { 'use workflow'; /* ... */ }
✗ import { workflow } from 'workflow';
Workflow functions are declared using the `'use workflow'` directive as the first line in the function body, not via a direct import. This instructs the Workflow SDK compiler to treat the function as a durable workflow orchestrator.
Step Function
✓ async function myStep() { 'use step'; /* ... */ }
✗ import { step } from 'workflow';
Step functions are marked with the `'use step'` directive, which identifies them as units of durable work within a workflow. They are automatically retried on failure and can perform side effects like network requests.
This quickstart demonstrates defining a durable workflow and two steps using the Workflow SDK directives, then triggering it from a client. It showcases durable `sleep` and simulates external API calls within steps.
import { start, sleep } from 'workflow';
// workflows/emailWorkflow.ts
export async function sendWelcomeEmailWorkflow(userId: string) {
'use workflow'; // Marks this as a durable workflow
console.log(`[Workflow] Starting welcome email for user: ${userId}`);
const emailContent = await fetchEmailContentStep(userId);
await sleep('10s'); // Simulate waiting for a pre-configured delay or external event
await sendEmailStep(userId, emailContent.subject, emailContent.body);
console.log(`[Workflow] Welcome email process completed for user: ${userId}`);
}
async function fetchEmailContentStep(userId: string) {
'use step'; // Marks this as a durable, retriable step
console.log(`[Step] Fetching email content for user: ${userId}`);
// In a real application, this would fetch from a database or template service
return {
subject: `Welcome to Our Service, User ${userId}!`,
body: `Dear User ${userId},\n\nThank you for joining!`
};
}
async function sendEmailStep(userId: string, subject: string, body: string) {
'use step'; // Marks this as a durable, retriable step
console.log(`[Step] Sending email to user: ${userId} with subject: ${subject}`);
// Simulate an external API call for sending emails
await new Promise(resolve => setTimeout(resolve, 2000)); // Simulate async email API call
console.log(`[Step] Email sent to ${userId}.`);
// In a real application, this would call an email service API like:
// await fetch('https://api.emailservice.com/send', { method: 'POST', body: JSON.stringify({ to: userId, subject, body }) });
}
// api/trigger-email.ts (Example of how to trigger the workflow)
// This could be an API route, a serverless function, or a CLI command
async function triggerWorkflow(userId: string) {
console.log(`[Client] Triggering workflow for user: ${userId}`);
const run = await start(sendWelcomeEmailWorkflow, { input: userId });
console.log(`[Client] Workflow started with Run ID: ${run.id}, Status: ${run.status}`);
return run;
}
// Example execution (e.g., in a main script or test)
async function main() {
const userToOnboard = 'user-123';
await triggerWorkflow(userToOnboard);
}
main().catch(console.error);
Debug
Known issues
breakingVersion 5.0.0-beta.1 introduced breaking changes to the `World` interface, specifically restructuring stream methods to use a `world.streams.*` namespace. Methods like `writeToStream` are now `streams.write` with `runId` as the first parameter. Additionally, `world.steps.get` now requires a `runId` argument. The Vercel Build Output API and standalone builder output also switched from CommonJS (CJS) to ECMAScript Modules (ESM).fixReview the migration guide for v5.0.0-beta.1 and update `World` interface implementations, stream method calls, and ensure your build environment properly handles ESM for Vercel deployments.
affects: >=5.0.0-beta.1
gotchaWorkflow functions marked with `'use workflow'` are designed to be deterministic and are sandboxed. They generally cannot perform side effects like direct network access (`fetch`) or file system operations. Such operations should be encapsulated within functions marked with `'use step'` to ensure durability and retryability.fixRefactor any side-effecting logic from your workflow function into a separate step function, marked with `'use step'`, and call that step from your workflow.
affects: >=4.0.0
gotchaEarly beta versions (e.g., `4.2.0-beta.77`) could experience 'dual-instance' issues with the `contextStorage` global when certain bundlers create multiple copies of the module. This could lead to unpredictable behavior in step contexts.fixUpgrade to a stable version of Workflow SDK (e.g., `4.2.0` or later) where this issue has been addressed, or ensure your bundler configuration avoids duplicate module instances.
affects: >=4.2.0-beta.77 <4.2.0
gotchaWhen using beta versions of Vercel SDKs (including Workflow SDK or related AI SDK), it is highly recommended to pin exact package versions (e.g., `"workflow": "5.0.0-beta.2"` instead of `"^5.0.0-beta.2"`). Beta versions can introduce breaking changes between minor or patch releases without following semantic versioning strictly.fixAlways use exact version pinning for beta releases in your `package.json` to prevent unexpected breaking changes on dependency updates, and review release notes carefully before upgrading.
affects: >=4.2.0-beta
Errors
Common errors & fixes
ReferenceError: require is not defined
Attempting to use CommonJS `require()` syntax in a project configured for ECMAScript Modules (ESM), or with a `workflow` version that is ESM-only.
fixEnsure your project is configured for ESM (e.g., `"type": "module"` in `package.json`) and use `import` statements. For older Node.js environments or projects, consider transpiling to CJS or using a bundler that supports ESM output. V5 betas are moving to ESM-only for some outputs.
Error: Workflow 'myWorkflow' is not registered.
The Workflow DevKit/SDK runtime cannot find the definition for the specified workflow function, often due to incorrect file paths, module resolution issues, or build misconfigurations.
fixVerify that your workflow file is correctly placed, exported, and accessible to the runtime. Ensure all necessary build steps and plugins (e.g., for Next.js or SvelteKit) are correctly configured to discover and register your workflows.
Error: Step 'myStep' is not registered.
Similar to workflow registration, the runtime cannot find the definition for a step function, typically caused by incorrect imports, file placement, or build process failures to register the step.
fixCheck the file path and export of your step function. Confirm that it includes the `'use step'` directive and that your build system correctly processes and registers step definitions. This often indicates a deployment mismatch.
Error: Serialization failed: Value `[object Object]` could not be serialized.
Workflows and steps exchange data that must be serializable (e.g., plain JavaScript objects, primitives). Passing complex objects like class instances, functions, or non-JSON-serializable values can cause this error.
fixEnsure all data passed to and from workflows and steps consists of serializable types (e.g., strings, numbers, booleans, arrays, plain objects). Convert complex objects to a serializable format before passing them.
Error: Workflow 'myWorkflow' execution timed out.
A workflow or an individual step exceeded its allotted execution time. This can happen if a step takes too long, an external dependency is slow, or `sleep` / `createWebhook` are not used for long pauses, causing compute resources to be held unnecessarily.
fixOptimize long-running operations within steps. For intentional pauses or waiting for external events, use durable primitives like `sleep()` or `createWebhook()` to suspend the workflow without consuming compute resources. Consider increasing timeout configurations if the operation is genuinely long-running and optimized.
Audit
Dependencies
@opentelemetry/apirequiredRequired for OpenTelemetry integration and observability features, enabling distributed tracing and metrics.