Skip to main content
AI Kit ships two workflow engines behind a single facade, WorkflowKit:
  • legacy (default) — the in-memory engine you build with createWorkflow / WorkflowBuilder. Zero extra dependencies, runs in-process, state lives in memory.
  • world — the Vercel Workflow SDK backed by a durable world: self-hosted Postgres (@workflow/world-postgres) or MongoDB (@workflow-worlds/mongodb). Runs survive restarts (durable replay, job queue, event log).
WorkflowKit lets you pick the engine through configuration; the default is always legacy, so existing code keeps working and legacy users never pull a single Vercel dependency.

When to use which

Use legacy for fast in-process orchestration and local development; use world when you need durability, suspension (sleep), and resumable long-running processes.

The WorkflowKit facade

Switch to the durable engine by setting engine: "world" and providing a world config:
  • kit.start() / kit.stop() manage the long-lived world worker. They are no-ops on legacy, so the same lifecycle code works for both engines.
  • kit.run(...) dispatches to the configured engine. You can override per call: kit.run(wf, input, { engine: "world" }).

Configuration

The constructor validates the config: engine: "world" without a world throws, and an unknown world.type throws. See the WorkflowKit API reference for the full surface.

Retrieving a run’s result

A world run is durable and decoupled: kit.run(fn, args) returns a WorldRunHandle (a pass-through of the SDK Run), not the output directly. To consume it synchronously — like the legacy await workflow.run() then .result — use kit.runAndWait:
Or keep the handle and await its returnValue (polls until the run completes):
returnValue rejects on failure (WorkflowRunFailedError) or cancellation (WorkflowRunCancelledError), carrying the original error — so wrap it in try/catch where legacy code inspected result.status. For deferred consumption, store runId and reconstitute the handle later with getRun(runId) from workflow/api.
runAndWait works for both engines (legacy returns the workflow output; world awaits returnValue) and throws on any non-success outcome — a clean drop-in for synchronously-consumed workflows being migrated.

Installing the world engine

The world engine lives in an optional package so the core stays lightweight:
If you select engine: "world" without @ai_kit/workflow-world installed, WorkflowKit throws a clear error telling you to install it.

Authoring world workflows

A world workflow is a plain async function marked with the "use workflow" directive; the real work goes in "use step" functions. These directives are detected at build time by the workflow/nitro compiler.
There is no defineWorldStep runtime helper. The Vercel compiler only instruments directives on top-level bindings (a named function, or an arrow/function bound directly to a const). Passing the function to a wrapper call would silently break detection — the step would run as plain, non-durable code. So you write the directive yourself and (optionally) annotate with the exported types.
@ai_kit/workflow-world exports WorldStep / WorldWorkflow types for ergonomics:

Control flow is native JavaScript

Because a world workflow is just an async function, you don’t need special primitives — use the language: The "use workflow" body must stay deterministic (no Date.now(), Math.random(), fetch, direct I/O) — put those effects inside "use step" functions.

Postgres: provision the schema once

Before the first run, the Postgres world needs its schema created (otherwise you get an undefined_table / 42P01 error). This is a one-time deployment step:
MongoDB does not need this step — it provisions on connection.

MongoDB (experimental)

The MongoDB world is community-maintained. Only the configuration changes; no application code differs from Postgres:

Build & runtime constraints

The Vercel Workflow SDK requires:
  1. A build step — Nitro compiles the "use workflow" / "use step" functions. Add the workflow/nitro module to your host app’s nitro.config.ts. AI Kit smooths runtime configuration but cannot remove this build step.
  2. A long-lived worker — the world polls the database for jobs, so the world engine is not compatible with pure serverless deployments.

Migrating a legacy workflow to the world engine

Migration is a rewrite from the declarative builder to an imperative function — there is no automatic translator. Before (legacy):
After (world):

Feature coverage

Because the world engine embeds the real Vercel SDK, it inherits all of its capabilities: durable execution, sleep, webhooks/hooks (human-in-the-loop), streaming, durable agents, automatic retries, and the npx workflow web observability dashboard. Advanced runtime APIs are used directly from the workflow package — the thin WorkflowKit facade only handles engine selection, lifecycle, and run dispatch.