Platformatic Workflow SDK Skill
You are an expert in building applications with the Vercel Workflow SDK
(workflow / @workflow/*) against @platformatic/world,
the self-hosted World adapter for Platformatic.
This skill helps users build apps that use workflows. It does not cover
deploying the Workflow Service — assume one is reachable at the URL the user
will supply as PLT_WORLD_SERVICE_URL.
Prerequisites Check
Before any workflow setup, verify:
Node.js Version:
@platformatic/worldrequires Node.js v22.19.0+node --versionWorkflow Service URL: The user needs a reachable Workflow Service.
- Local dev: typically
http://localhost:3042(started vianpx @platformatic/workflow postgresql://...). - K8s: provided by the Platformatic control plane (ICC) or operator.
If the user does not have one, point them at
@platformatic/workflowquick start before continuing — but do not try to start the service from this skill.
- Local dev: typically
Existing package.json: This skill installs into an existing Node app.
Command Router
Based on user input ($ARGUMENTS), route to the appropriate workflow:
| Input Pattern | Action |
|---|---|
init, setup, add, (empty) |
Run Detect Framework + World Setup |
next, nextjs, next.js |
Run Next.js Setup |
node, express, koa, generic |
Run Generic Node.js Setup |
fastify |
Run Fastify Setup (with plugin) |
author, write, use workflow, use step, step, hook, sleep, stream |
Read references/authoring.md |
trigger, start, run |
Run Trigger a Workflow guidance |
build, standalone |
Run Standalone Build Workflow |
env, config |
Run Environment Configuration |
status, check |
Run Status Check |
troubleshoot, debug |
Read references/troubleshooting.md |
Detect Framework + World Setup
When the user asks to "add workflow" without specifying a framework:
- Detect the framework by inspecting the project:
next.config.{js,ts,mjs}ornextinpackage.json→ Next.js Setupfastifyinpackage.json→ Fastify Setup (with plugin) (the plugin is optional — also offer plain Node setup)- Any other Node server (Express/Koa/Hono/plain HTTP) → Generic Node.js Setup
- Confirm the detection with the user before generating files.
In all cases, the core install is the same:
npm install workflow @platformatic/world
workflow is the Vercel SDK; @platformatic/world is the World adapter that
points the SDK at the Platformatic Workflow Service.
Then read:
- references/world.md — full client reference (env
vars,
createWorld,world.start(), framework wiring). - references/authoring.md — how to write
workflows and steps with the Vercel SDK (
'use workflow','use step', retries, hooks, sleeps, streams, determinism rules).
Continue with the framework-specific section below for the wiring details.
Next.js Setup
When the user runs 'use workflow' / 'use step' files inside a Next.js app:
- Install:
npm install workflow @platformatic/world - Read references/world.md — section "Next.js wiring".
- Create
instrumentation.tsat the project root:
This registers the app's queue handler endpoints (// instrumentation.ts export async function register () { if (process.env.PLT_WORLD_SERVICE_URL) { const { createWorld } = await import('@platformatic/world') const world = createWorld() await world.start?.() } }/.well-known/workflow/v1/{flow,step,webhook}) with the Workflow Service on boot. In K8s + ICC,world.start()is a no-op (ICC registers handlers via the control plane). - Set environment variables in
.env.local:WORKFLOW_TARGET_WORLD=@platformatic/world PLT_WORLD_SERVICE_URL=http://localhost:3042 # Optional: PLT_WORLD_APP_ID=my-app-id # defaults to package.json name PLT_WORLD_DEPLOYMENT_VERSION=local # auto-detected in K8s - Author workflows the standard Vercel way — the SDK transforms
'use workflow'/'use step'files automatically inside Next.js. - Trigger runs from a route handler or server action:
import { start } from 'workflow/api' import { handleSignup } from '@/workflows/signup' await start(handleSignup, [email]) - Verify with
npm run devand watch the Next.js logs for the[workflow]handler registration line.
Generic Node.js Setup
For Node servers without a framework-specific transform (Express, Koa, Hono,
plain http), the SDK still works but you call world.start() explicitly.
- Install:
npm install workflow @platformatic/world - Read references/world.md — section "Manual world.start()".
- Call
world.start()once during server boot, before accepting traffic:import { createWorld } from '@platformatic/world' const world = createWorld() await world.start?.() // ...then app.listen(PORT) - Set environment variables (see references/world.md).
- The Vercel SDK's transform is required to author
'use workflow'/'use step'files. If the host framework does not transform them, use the standalone build (see Standalone Build Workflow) and mount the resulting handlers on your routes — or use the Fastify plugin which does this for you.
Fastify Setup (with plugin)
When the user wants to host Vercel Workflow SDK workflows inside a Fastify
app, recommend @platformatic/workflow-fastify. It is optional — they can
also do the work manually following the Generic Node.js Setup.
- Install:
npm install fastify workflow @platformatic/world @platformatic/workflow-fastify - Read references/fastify.md.
- Author workflow files (e.g.
workflows/signup.ts) with'use workflow'/'use step'. - Build the standalone bundles (see Standalone Build Workflow below):
This emitsnpx workflow build --target standaloneflow,step,webhook, andmanifest.jsonunder.well-known/workflow/v1/. - Register the plugin in your Fastify app:
import Fastify from 'fastify' import { start } from 'workflow/api' import workflowFastify from '@platformatic/workflow-fastify' const app = Fastify() await app.register(workflowFastify) app.post('/api/signup', async (req) => { const run = await start( { workflowId: app.workflows.handleSignup }, [req.body.email] ) return { runId: run.runId } }) await app.listen({ port: Number(process.env.PORT) }) - Set environment variables (same set as Next.js / generic Node).
- Run the build before each start (or wire it into your build script):
npx workflow build --target standalone && node server.js
The plugin:
- Mounts
flow,step,webhookhandlers under/.well-known/workflow/v1/. - Decorates the Fastify instance with
app.workflows(name → workflowId map). - Calls
world.start()on boot to register the queue handler.
Trigger a Workflow
When the user asks how to start a workflow run from application code:
- Import the trigger API from the Vercel SDK, not from
@platformatic/world:import { start } from 'workflow/api' - Two ways to identify the workflow:
- By imported reference (works inside files the SDK transforms — typically
Next.js routes/actions):
import { handleSignup } from '@/workflows/signup' const run = await start(handleSignup, [email]) - By workflowId string (works anywhere — required outside transformed
files, e.g. plain Fastify route handlers):
const run = await start({ workflowId: app.workflows.handleSignup }, [email])
- By imported reference (works inside files the SDK transforms — typically
Next.js routes/actions):
- To resume a hook (webhook or human-in-the-loop):
import { resumeHook } from 'workflow/api' await resumeHook(token, payload) - Tell the user the trigger call is just an HTTP POST to the Workflow Service — no special transport is required in the calling process.
Standalone Build Workflow
The Vercel SDK's workflow build --target standalone produces self-contained
bundles for hosts that don't have a built-in SDK transform (e.g. Fastify,
plain Node, scripts).
- The build reads
'use workflow'/'use step'files from your source tree. - It writes to
<buildDir>/.well-known/workflow/v1/:flow— workflow orchestration handler (POST, WebRequest => Response)step— step execution handlerwebhook— webhook resume handlermanifest.json— workflow/step ids and graph
- Extensions vary by SDK version: v5 emits
.mjs; v4 emits.js(flow/step CommonJS, webhook ESM).@platformatic/workflow-fastifyhandles both transparently. - Re-run the build whenever workflow source files change. In CI, run it as a pre-build step before the host app is packaged.
- Don't commit
.well-known/workflow/v1/— add it to.gitignorealongsidedist/.
npx workflow build --target standalone
Inside Next.js you do not need this — the Next plugin transforms workflows inline. The standalone build is for non-Next hosts.
Environment Configuration
The SDK and @platformatic/world read these environment variables:
| Variable | Required | Default | Description |
|---|---|---|---|
WORKFLOW_TARGET_WORLD |
Yes | — | Set to @platformatic/world to select this adapter |
PLT_WORLD_SERVICE_URL |
Yes | — | Workflow Service base URL (e.g. http://localhost:3042) |
PLT_WORLD_APP_ID |
No | package.json name |
Application identifier (multi-tenant routing) |
PLT_WORLD_DEPLOYMENT_VERSION |
No | K8s label or 'local' |
Version each run pins to |
PORT |
No | — | Used by world.start() to register the callback URL locally |
In K8s, PLT_WORLD_DEPLOYMENT_VERSION is auto-detected from the pod's
plt.dev/version label via the K8s API — usually leave it unset there.
For local development without K8s, the Workflow Service runs in single-tenant
mode and any appId is accepted.
Status Check
When user runs /workflow status:
Node.js Version
node --versionCheck if >= v22.19.0.
Dependencies present
node -e "require('workflow/package.json')" node -e "require('@platformatic/world/package.json')"Required env vars set
node -e "console.log({world:process.env.WORKFLOW_TARGET_WORLD, url:process.env.PLT_WORLD_SERVICE_URL})"WORKFLOW_TARGET_WORLDmust equal@platformatic/world.PLT_WORLD_SERVICE_URLmust be a reachable URL.Service reachable
curl -fsS "$PLT_WORLD_SERVICE_URL/api/v1/apps/default/runs" >/dev/null && echo OKFor Next.js:
instrumentation.tsexists at the project root and callsworld.start()insideregister().For Fastify with plugin:
.well-known/workflow/v1/manifest.jsonexists (i.e. the standalone build has been run).
Report findings in a clear format:
Workflow SDK Configuration Status
=================================
Node.js Version: vX.X.X [OK/UPGRADE NEEDED]
workflow installed: [vX.X.X/Missing]
@platformatic/world: [vX.X.X/Missing]
WORKFLOW_TARGET_WORLD: [@platformatic/world/Missing]
PLT_WORLD_SERVICE_URL: [URL/Missing]
Service reachable: [OK/Unreachable]
Framework wiring: [instrumentation.ts/Fastify plugin/manual]
Standalone build: [Present/Not built/N/A]
Important Notes
@platformatic/worldis a runtime drop-in for@workflow/world. The Vercel SDK calls into it via the standard World interface; nothing application-level changes.world.start()must run exactly once per process before accepting traffic. Calling it twice is harmless (idempotent) but wastes a call. Skipping it means queue messages will never reach this process and runs will hang inpending.- Under K8s + ICC,
world.start()is a no-op — ICC registers handlers centrally via the control plane. - Spec version:
@platformatic/worlddeclares spec v3 (CBOR queue transport). It interoperates with v2 servers and v2 clients, so version skew during rollout is safe. - SDK compatibility: works at runtime against both
workflow@4.2.x(stable) andworkflow@5.0.0-beta.x(next). The world is typed against@workflow/world@4.1.1but exposes the v5streams.*namespace at runtime alongside the v4 flat methods.
Troubleshooting
For common issues (runs stuck in pending, world.start() failing, missing
callback URL, K8s deployment version mismatch), read
references/troubleshooting.md.
Source: platformatic/skills — distributed by TomeVault.