Workflow
@vitehub/workflow gives Vite and Nitro apps one way to define long-running work, start a named workflow from request code, and observe the run through Cloudflare Workflows or Vercel.
Use Workflow when background work has multiple steps, needs a stable run id, or should be visible after the request that started it has already returned.
import { runWorkflow } from '@vitehub/workflow'
import type { WelcomePayload } from '../workflows/welcome'
export default defineEventHandler(async (event) => {
const payload = await readBody<WelcomePayload>(event)
const run = await runWorkflow('welcome', payload)
return { ok: true, run }
})
import { defineWorkflow } from '@vitehub/workflow'
export type WelcomePayload = {
email: string
marker?: string
}
export default defineWorkflow<WelcomePayload>(async ({ payload }) => {
return {
message: `Welcome ${payload.email}`,
marker: payload.marker,
}
})
{
"ok": true,
"run": {
"id": "wrun_lvn4hx4f_x8k2p9s1",
"provider": "cloudflare",
"status": "queued"
}
}
What Workflow solves
Queues are a good fit for one handler. Workflows are better when the operation has an identity and the caller may need to ask what happened later.
Workflow keeps that boundary explicit:
Named flows
defineWorkflow() definition instead of scattering logic across request handlers.Portable starts
runWorkflow() or deferWorkflow() the same way on Cloudflare and Vercel.Run observation
Generated registry
One portable flow
The same application shape works across providers:
- Register the Vite plugin or Nitro module.
- Choose
cloudflareorvercelinworkflow.provider. - Define a named workflow with
defineWorkflow(). - Start it with
runWorkflow(name, payload). - Check it later with
getWorkflowRun(name, id)when the provider can report status.
Discovery model
Nitro discovers workflow definitions from server/workflows/**.
The workflow name comes from the path under server/workflows, without the file extension. server/workflows/email/welcome.ts becomes email/welcome.
Supported providers
Start here
Start with Quickstart for the smallest complete setup. Use the primitive comparison when you are deciding between KV, Blob, Queue, Sandbox, Workflow, or inline request code.

