workflow 5.0.0-beta.4 → 5.0.0-beta.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/README.md +63 -20
  2. package/dist/api-workflow.d.ts +1 -1
  3. package/dist/api-workflow.d.ts.map +1 -1
  4. package/dist/api-workflow.js +1 -1
  5. package/dist/api.d.ts +5 -1
  6. package/dist/api.d.ts.map +1 -1
  7. package/dist/api.js +12 -2
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +6 -1
  11. package/dist/internal/builtins.d.ts +17 -0
  12. package/dist/internal/builtins.d.ts.map +1 -1
  13. package/dist/internal/builtins.js +65 -1
  14. package/dist/internal/errors.d.ts +1 -1
  15. package/dist/internal/errors.d.ts.map +1 -1
  16. package/dist/internal/errors.js +2 -2
  17. package/dist/nest-builder.d.ts +2 -0
  18. package/dist/nest-builder.d.ts.map +1 -0
  19. package/dist/nest-builder.js +2 -0
  20. package/dist/nest-vercel-builder.d.ts +2 -0
  21. package/dist/nest-vercel-builder.d.ts.map +1 -0
  22. package/dist/nest-vercel-builder.js +2 -0
  23. package/dist/observability.d.ts +1 -1
  24. package/dist/observability.js +2 -2
  25. package/dist/runtime.d.ts +2 -1
  26. package/dist/runtime.d.ts.map +1 -1
  27. package/dist/runtime.js +5 -2
  28. package/docs/ai/chat-session-modeling.mdx +7 -3
  29. package/docs/ai/defining-tools.mdx +2 -2
  30. package/docs/ai/index.mdx +30 -25
  31. package/docs/ai/message-queueing.mdx +10 -10
  32. package/docs/ai/resumable-streams.mdx +9 -1
  33. package/docs/api-reference/index.mdx +24 -0
  34. package/docs/api-reference/meta.json +8 -0
  35. package/docs/api-reference/vitest/index.mdx +28 -7
  36. package/docs/api-reference/workflow/create-hook.mdx +79 -0
  37. package/docs/api-reference/workflow/create-webhook.mdx +1 -0
  38. package/docs/api-reference/workflow/define-hook.mdx +26 -24
  39. package/docs/api-reference/workflow/fatal-error.mdx +29 -7
  40. package/docs/api-reference/workflow/fetch.mdx +8 -4
  41. package/docs/api-reference/workflow/index.mdx +3 -0
  42. package/docs/api-reference/workflow/set-attributes.mdx +61 -0
  43. package/docs/api-reference/workflow/sleep.mdx +1 -1
  44. package/docs/api-reference/workflow-ai/durable-agent.mdx +7 -45
  45. package/docs/api-reference/workflow-ai/index.mdx +2 -2
  46. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +44 -1
  47. package/docs/api-reference/workflow-api/get-hook-by-token.mdx +9 -0
  48. package/docs/api-reference/workflow-api/get-run.mdx +25 -0
  49. package/docs/api-reference/workflow-api/index.mdx +6 -8
  50. package/docs/api-reference/workflow-api/resume-hook.mdx +60 -1
  51. package/docs/api-reference/workflow-api/resume-webhook.mdx +6 -4
  52. package/docs/api-reference/workflow-api/start.mdx +39 -6
  53. package/docs/api-reference/workflow-astro/index.mdx +18 -0
  54. package/docs/api-reference/workflow-astro/meta.json +4 -0
  55. package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
  56. package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
  57. package/docs/api-reference/workflow-errors/index.mdx +88 -0
  58. package/docs/api-reference/workflow-errors/meta.json +6 -0
  59. package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
  60. package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
  61. package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
  62. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +16 -6
  63. package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
  64. package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
  65. package/docs/api-reference/workflow-globals.mdx +4 -1
  66. package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +33 -0
  67. package/docs/api-reference/workflow-nest/index.mdx +31 -0
  68. package/docs/api-reference/workflow-nest/meta.json +9 -0
  69. package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
  70. package/docs/api-reference/workflow-nest/workflow-controller.mdx +40 -0
  71. package/docs/api-reference/workflow-nest/workflow-module.mdx +74 -0
  72. package/docs/api-reference/workflow-next/with-workflow.mdx +56 -2
  73. package/docs/api-reference/workflow-nitro/index.mdx +60 -0
  74. package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
  75. package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
  76. package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
  77. package/docs/api-reference/workflow-observability/index.mdx +64 -0
  78. package/docs/api-reference/workflow-observability/meta.json +11 -0
  79. package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
  80. package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
  81. package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
  82. package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
  83. package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
  84. package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
  85. package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +7 -10
  86. package/docs/api-reference/workflow-runtime/health-check.mdx +50 -0
  87. package/docs/api-reference/workflow-runtime/index.mdx +43 -0
  88. package/docs/api-reference/workflow-runtime/meta.json +12 -0
  89. package/docs/api-reference/workflow-runtime/set-world.mdx +49 -0
  90. package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +42 -0
  91. package/docs/api-reference/workflow-runtime/world/analytics.mdx +138 -0
  92. package/docs/api-reference/{workflow-api → workflow-runtime}/world/index.mdx +10 -10
  93. package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
  94. package/docs/api-reference/{workflow-api → workflow-runtime}/world/queue.mdx +8 -6
  95. package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +18 -5
  96. package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +2 -2
  97. package/docs/api-reference/workflow-serde/index.mdx +0 -1
  98. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +1 -2
  99. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +2 -2
  100. package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
  101. package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
  102. package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
  103. package/docs/api-reference/workflow-vite/index.mdx +18 -0
  104. package/docs/api-reference/workflow-vite/meta.json +4 -0
  105. package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
  106. package/docs/changelog/attributes-mvp.mdx +380 -0
  107. package/docs/changelog/eager-processing.mdx +269 -0
  108. package/docs/changelog/index.mdx +3 -1
  109. package/docs/changelog/lazy-event-creation.md +127 -0
  110. package/docs/changelog/meta.json +9 -1
  111. package/docs/changelog/resilient-resume.mdx +22 -0
  112. package/docs/changelog/resilient-start.mdx +31 -283
  113. package/docs/changelog/step-message-ownership.mdx +360 -0
  114. package/docs/changelog/turbo-mode.md +87 -0
  115. package/docs/comparisons/index.mdx +66 -0
  116. package/docs/comparisons/meta.json +11 -0
  117. package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
  118. package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
  119. package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
  120. package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
  121. package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
  122. package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +103 -0
  123. package/docs/configuration/build-and-diagnostics.mdx +70 -0
  124. package/docs/configuration/cli-and-web-ui.mdx +182 -0
  125. package/docs/configuration/framework-options.mdx +165 -0
  126. package/docs/configuration/index.mdx +32 -0
  127. package/docs/configuration/meta.json +12 -0
  128. package/docs/configuration/runtime-tuning.mdx +276 -0
  129. package/docs/configuration/worlds.mdx +275 -0
  130. package/docs/cookbook/advanced/child-workflows.mdx +203 -256
  131. package/docs/cookbook/advanced/meta.json +1 -1
  132. package/docs/cookbook/advanced/publishing-libraries.mdx +33 -24
  133. package/docs/cookbook/advanced/serializable-steps.mdx +12 -4
  134. package/docs/cookbook/advanced/upgrading-workflows.mdx +199 -0
  135. package/docs/cookbook/agent-patterns/agent-cancellation.mdx +34 -75
  136. package/docs/cookbook/agent-patterns/durable-agent.mdx +14 -142
  137. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +11 -3
  138. package/docs/cookbook/common-patterns/batching.mdx +4 -0
  139. package/docs/cookbook/common-patterns/idempotency.mdx +40 -52
  140. package/docs/cookbook/common-patterns/rate-limiting.mdx +5 -1
  141. package/docs/cookbook/common-patterns/saga.mdx +6 -2
  142. package/docs/cookbook/common-patterns/scheduling.mdx +12 -0
  143. package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +4 -0
  144. package/docs/cookbook/common-patterns/timeouts.mdx +6 -1
  145. package/docs/cookbook/common-patterns/webhooks.mdx +4 -0
  146. package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -16
  147. package/docs/cookbook/index.mdx +3 -3
  148. package/docs/cookbook/integrations/ai-sdk.mdx +64 -28
  149. package/docs/cookbook/integrations/chat-sdk.mdx +17 -0
  150. package/docs/cookbook/integrations/sandbox.mdx +17 -0
  151. package/docs/{deploying/index.mdx → deploying.mdx} +7 -7
  152. package/docs/errors/abort-signal-timeout-in-workflow.mdx +84 -0
  153. package/docs/errors/corrupted-event-log.mdx +5 -5
  154. package/docs/errors/deployment-mismatch.mdx +71 -0
  155. package/docs/errors/fetch-in-workflow.mdx +4 -0
  156. package/docs/errors/hook-conflict.mdx +60 -4
  157. package/docs/errors/index.mdx +1 -35
  158. package/docs/errors/node-js-module-in-workflow.mdx +4 -0
  159. package/docs/errors/replay-divergence.mdx +27 -0
  160. package/docs/errors/runtime-decryption-failed.mdx +77 -0
  161. package/docs/errors/serialization-failed.mdx +4 -0
  162. package/docs/errors/start-invalid-workflow-function.mdx +4 -0
  163. package/docs/errors/step-executed-multiple-times.mdx +23 -0
  164. package/docs/errors/step-not-registered.mdx +1 -1
  165. package/docs/errors/timeout-in-workflow.mdx +4 -0
  166. package/docs/errors/webhook-response-not-sent.mdx +4 -0
  167. package/docs/foundations/cancellation.mdx +459 -0
  168. package/docs/foundations/errors-and-retries.mdx +7 -3
  169. package/docs/foundations/hooks.mdx +29 -0
  170. package/docs/foundations/idempotency.mdx +243 -11
  171. package/docs/foundations/index.mdx +1 -23
  172. package/docs/foundations/meta.json +3 -1
  173. package/docs/foundations/serialization.mdx +77 -41
  174. package/docs/foundations/starting-workflows.mdx +79 -2
  175. package/docs/foundations/streaming.mdx +14 -23
  176. package/docs/foundations/versioning.mdx +263 -0
  177. package/docs/getting-started/astro.mdx +12 -2
  178. package/docs/getting-started/express.mdx +6 -2
  179. package/docs/getting-started/fastify.mdx +6 -2
  180. package/docs/getting-started/hono.mdx +6 -2
  181. package/docs/getting-started/index.mdx +16 -10
  182. package/docs/getting-started/meta.json +4 -1
  183. package/docs/getting-started/nestjs.mdx +77 -3
  184. package/docs/getting-started/next.mdx +12 -6
  185. package/docs/getting-started/nitro.mdx +28 -2
  186. package/docs/getting-started/nuxt.mdx +6 -2
  187. package/docs/getting-started/python.mdx +24 -18
  188. package/docs/getting-started/react-router/index.mdx +33 -0
  189. package/docs/getting-started/react-router/meta.json +5 -0
  190. package/docs/getting-started/react-router/v7.mdx +237 -0
  191. package/docs/getting-started/react-router/v8.mdx +232 -0
  192. package/docs/getting-started/sveltekit.mdx +12 -2
  193. package/docs/getting-started/tanstack-start.mdx +245 -0
  194. package/docs/getting-started/vite.mdx +6 -2
  195. package/docs/how-it-works/cancellation.mdx +287 -0
  196. package/docs/how-it-works/code-transform.mdx +21 -17
  197. package/docs/how-it-works/encryption.mdx +5 -5
  198. package/docs/how-it-works/event-sourcing.mdx +6 -6
  199. package/docs/how-it-works/framework-integrations.mdx +96 -337
  200. package/docs/how-it-works/meta.json +2 -1
  201. package/docs/internal/index.mdx +21 -0
  202. package/docs/internal/meta.json +10 -0
  203. package/docs/internal/nitro-native-build.mdx +38 -0
  204. package/docs/internal/nitro-web-ui.mdx +24 -0
  205. package/docs/internal/serializable-abort-controller.mdx +148 -0
  206. package/docs/meta.json +2 -2
  207. package/docs/observability/attributes.mdx +112 -0
  208. package/docs/observability/index.mdx +20 -1
  209. package/docs/observability/meta.json +1 -1
  210. package/docs/observability/tracing.mdx +124 -0
  211. package/docs/testing/index.mdx +2 -2
  212. package/package.json +17 -13
  213. package/docs/api-reference/workflow-api/world/meta.json +0 -4
  214. package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
  215. package/docs/cookbook/advanced/distributed-abort-controller.mdx +0 -318
  216. package/docs/deploying/building-a-world.mdx +0 -251
  217. package/docs/deploying/meta.json +0 -4
  218. package/docs/deploying/world/local-world.mdx +0 -84
  219. package/docs/deploying/world/meta.json +0 -4
  220. package/docs/deploying/world/postgres-world.mdx +0 -222
  221. package/docs/deploying/world/vercel-world.mdx +0 -179
  222. package/docs/migration-guides/index.mdx +0 -34
  223. package/docs/migration-guides/meta.json +0 -9
  224. package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -363
  225. package/docs/migration-guides/migrating-from-inngest.mdx +0 -314
  226. package/docs/migration-guides/migrating-from-temporal.mdx +0 -318
  227. package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -337
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: Workflow SDK vs AWS Step Functions
3
+ description: How the Workflow SDK compares to AWS Step Functions — plain TypeScript control flow versus declarative Amazon States Language JSON, plus a concept-mapping migration guide.
4
+ type: conceptual
5
+ summary: AWS Step Functions is a managed state-machine orchestrator authored in declarative ASL JSON. The Workflow SDK expresses the same orchestration as plain TypeScript.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/foundations/errors-and-retries
10
+ - /docs/foundations/hooks
11
+ - /worlds/vercel
12
+ ---
13
+
14
+ [AWS Step Functions](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html) is a mature, managed orchestrator that runs **state machines defined in Amazon States Language (ASL)** — a declarative JSON DSL. The headline contrast with the Workflow SDK is the authoring model: you assemble a state machine (JSON or a visual editor) instead of writing plain control-flow code.
15
+
16
+ <Callout type="info">
17
+ **Choose the Workflow SDK** when you want orchestration as ordinary TypeScript (`await`, `if`, `Promise.all`, `try/catch`) that lives in your app, portable off a single cloud, with built-in streaming. **Choose Step Functions** when you're deep in the AWS ecosystem and want a managed engine with native optimized integrations to 200+ AWS services and the broadest compliance footprint.
18
+ </Callout>
19
+
20
+ ## At a glance
21
+
22
+ | | Workflow SDK | AWS Step Functions |
23
+ | --- | --- | --- |
24
+ | **Authoring** | Plain TypeScript: `"use workflow"` orchestrators calling `"use step"` functions | **Declarative ASL JSON** (or Workflow Studio visual editor / CDK) — not plain code |
25
+ | **Durability model** | Event log + deterministic replay | Managed state machine. **Standard** = exactly-once, up to 1 year; **Express** = at-least-once, up to 5 minutes |
26
+ | **Control flow** | `await`, `if`/`switch`, `Promise.all`, `try/catch` | `Task` / `Choice` / `Wait` / `Parallel` / `Map` states wired with `Next` |
27
+ | **Where it runs** | Your platform (Vercel managed or self-host) | AWS-managed; tasks run in Lambda or 200+ integrated AWS services |
28
+ | **Languages** | TypeScript / JS (Python beta) | ASL JSON for the machine; tasks can be any language (via Lambda) |
29
+ | **Human-in-the-loop** | `createHook()` / `createWebhook()` | `.waitForTaskToken` callback (Standard only) |
30
+ | **Streaming** | Native durable, resumable streaming to clients | No native client streaming |
31
+ | **Versioning** | Runs pinned to immutable deployment | Published versions are immutable; aliases route (≤2 versions) for canary/rollback; **in-flight executions keep their start-time definition** |
32
+ | **Portability** | Apache-2.0; runs anywhere Node runs | Proprietary, AWS-only; ASL is AWS-specific — high lock-in |
33
+ | **Pricing** | SDK free; pay your platform | **Standard:** $0.025 / 1K state transitions. **Express:** $1 / M requests + GB-second duration |
34
+ | **Limits** | 50 MB payload; 2 GB/run; no duration cap ([Vercel World limits](https://vercel.com/docs/workflows/pricing)) | 256 KB payload between states; Standard 25K history events / 1 year; Express 5 minutes |
35
+ | **AI** | `WorkflowAgent` in the AI SDK; durable streaming | Bedrock integration + a preview AgentCore "InvokeHarness" task; no native client streaming |
36
+
37
+ **What the limits mean in practice:** the 256 KB cap on payloads between states is the binding constraint for AI workloads — virtually any model context or tool transcript has to round-trip through S3 with claim-check plumbing — and Standard executions cap history at 25K events. The [Vercel World limits](https://vercel.com/docs/workflows/pricing) are 50 MB per payload and 2 GB of state per run.
38
+
39
+ ## Code vs. JSON
40
+
41
+ The defining difference: in Step Functions even "call one Lambda" requires a state-machine shell, and orchestration logic is expressed as ASL states (`Choice`, `Wait`, `Parallel`, `Map`). In the Workflow SDK it's ordinary TypeScript — transitions are `await`, branches are `if`, parallelism is `Promise.all`, and error handling is `try/catch`. That keeps orchestration in the same language, repo, and tests as the rest of your app, and removes the orchestrator/compute split (per-task Lambdas, IAM roles, callback queues).
42
+
43
+ The trade-off: Step Functions' optimized service integrations call AWS services (DynamoDB, SQS, EventBridge, Bedrock, `ecs:runTask.sync`, …) declaratively. In the Workflow SDK those become ordinary SDK calls inside `"use step"` functions — you own the credentials, retries, and any polling.
44
+
45
+ ## Migrating from Step Functions
46
+
47
+ This guide assumes **Standard** workflows. Express workflows have different semantics (at-least-once, 5-minute max, no execution history) and may be better kept on Step Functions or moved to a queue consumer.
48
+
49
+ | AWS Step Functions | Workflow SDK | Note |
50
+ | --- | --- | --- |
51
+ | State machine (ASL JSON) | `"use workflow"` function | The workflow function *is* the state machine. |
52
+ | Task state / Lambda | `"use step"` function | Side effects go in steps; no separate Lambda. |
53
+ | Choice state | `if` / `else` / `switch` | Native control flow. |
54
+ | Wait state | `sleep()` | `sleep('1m')` or `sleep(date)`. |
55
+ | Parallel state | `Promise.all()` | Standard concurrency. |
56
+ | Map state | `for` loop / bounded `Promise.all` (e.g. `p-limit`) / step-wrapped `start()` per item for large fan-out | Match the original concurrency mode. |
57
+ | Retry / Catch | `maxRetries`, `RetryableError`, `FatalError`; `try/catch` for compensation | Retry logic moves to step boundaries. |
58
+ | `.waitForTaskToken` | `createHook()` / `createWebhook()` | Hooks for typed signals; webhooks for HTTP. |
59
+ | Child state machine (`StartExecution`) | `"use step"` wrapper around `start()` / `getRun()` | Return the `Run` object for deep-linking. |
60
+
61
+ A single `Task` state and its Lambda collapse into two directive-tagged functions:
62
+
63
+ ```typescript title="workflows/order.ts"
64
+ export async function processOrder(orderId: string) {
65
+ 'use workflow'; // [!code highlight]
66
+ const order = await loadOrder(orderId);
67
+ if (order.total > 1000) await reviewManually(order); // Choice → if
68
+ await chargePayment(order);
69
+ }
70
+
71
+ async function loadOrder(id: string) {
72
+ 'use step'; // [!code highlight]
73
+ return fetch(`https://example.com/api/orders/${id}`).then((r) => r.json());
74
+ }
75
+ ```
76
+
77
+ A `.waitForTaskToken` callback becomes a hook — no SQS queue, task token, or callback Lambda:
78
+
79
+ ```typescript title="workflows/refund.ts"
80
+ import { createHook } from 'workflow';
81
+
82
+ export async function refundWorkflow(refundId: string) {
83
+ 'use workflow';
84
+ using approval = createHook<{ approved: boolean }>({
85
+ token: `refund:${refundId}:approval`, // [!code highlight]
86
+ });
87
+ return await approval; // resumed via resumeHook(), not SendTaskSuccess
88
+ }
89
+ ```
90
+
91
+ <Callout type="info">
92
+ Install the migration skill to translate a state machine automatically:
93
+
94
+ ```bash
95
+ npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk
96
+ ```
97
+ </Callout>
98
+
99
+ ### Step Functions features without a direct Workflow SDK equivalent
100
+
101
+ Each row is a Step Functions capability the Workflow SDK does not replicate one-to-one, paired with how to cover it on the Workflow SDK side:
102
+
103
+ | Step Functions feature | How to cover it with the Workflow SDK |
104
+ | --- | --- |
105
+ | Express workflows | At-least-once and 5-minute duration fit the durable-replay model poorly; keep them on Step Functions or move to a queue consumer |
106
+ | Distributed Map (up to 10,000 concurrent children, S3 item sources) | Fan out with step-wrapped `start()` per item, then bound concurrency with `p-limit` |
107
+ | Optimized AWS service integrations | Become ordinary SDK calls inside steps; `.sync` waits become explicit polling or hooks |
108
+ | Per-state IAM roles | Steps share the deployment's credentials; scope secrets at deploy time |
109
+
110
+ ---
111
+ *Compiled from public documentation. Step Functions pricing/limits are region-specific (figures are us-east-1); verify against [the AWS pricing page](https://aws.amazon.com/step-functions/pricing/). Not based on head-to-head benchmarks.*
@@ -0,0 +1,71 @@
1
+ ---
2
+ title: Workflow SDK vs Cloudflare Workflows
3
+ description: How the Workflow SDK compares to Cloudflare Workflows — both are durable replay engines, but they handle versioning, encryption, portability, and global distribution very differently.
4
+ type: conceptual
5
+ summary: Cloudflare Workflows is a durable engine on Workers and Durable Objects. It and the Workflow SDK both replay, but differ on versioning safety, encryption, and lock-in.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/how-it-works/event-sourcing
10
+ - /docs/foundations/streaming
11
+ - /worlds/building-a-world
12
+ ---
13
+
14
+ [Cloudflare Workflows](https://developers.cloudflare.com/workflows/) is a durable-execution engine built on Cloudflare Workers and SQLite-backed Durable Objects. It's the closest architectural peer to the Workflow SDK — both persist progress and replay to survive failures — which makes the differences in **versioning safety, encryption, and portability** the deciding factors.
15
+
16
+ <Callout type="info">
17
+ **Choose the Workflow SDK** when you want an open-source, portable engine that runs in your existing app (and off a single vendor), deployment-pinned versioning, and application-level E2E encryption. **Choose Cloudflare Workflows** when you're already all-in on Cloudflare.
18
+ </Callout>
19
+
20
+ ## At a glance
21
+
22
+ | | Workflow SDK | Cloudflare Workflows |
23
+ | --- | --- | --- |
24
+ | **Category** | Open-source durable-functions SDK; portable backends | Durable execution engine, hosted on Cloudflare |
25
+ | **Durability model** | Event log + deterministic replay | Step-result **memoization** in SQLite-backed Durable Objects + deterministic re-calculation ("game-loop") |
26
+ | **Authoring** | `"use workflow"` / `"use step"` in plain async TS, in your app | Class extends `WorkflowEntrypoint`; explicit `step.do(name, cb)` wrapping; Cloudflare Workers only |
27
+ | **Where it runs** | Your platform (Vercel managed, or self-host) | Cloudflare only — both orchestration and execution run on-network (engine ↔ step over internal RPC) |
28
+ | **Versioning** | Runs pinned to their immutable deployment — safe by default | **No version pinning** — running instances resume on the *latest* deployed code; changing step names/order can desync the cached replay. No patching API |
29
+ | **Encryption** | Per-run AES-256-GCM **end-to-end** encryption | **At-rest only** (AES-256, Cloudflare-managed keys) + TLS; no E2E, no customer-managed keys |
30
+ | **AI & streaming** | `WorkflowAgent` in the AI SDK; native resumable streaming | Durable agents via Workflows + the Agents SDK; resumable streaming buffered in SQLite (mid-call eviction needs opt-in `chatRecovery`) |
31
+ | **Performance** | No-penalty resume; scale-to-zero; up to 100K concurrency (Vercel) | **~0 ms isolate cold starts**; 50K concurrent instances; global Anycast (330+ cities) — strongest cold-start and edge story |
32
+ | **Portability** | Apache-2.0; World abstraction; self-hostable | Engine proprietary; tied to Durable Objects; **highest lock-in** of these tools |
33
+ | **Pricing** | SDK free; pay your platform | Workers Standard: requests + CPU-time + storage + per-step ($0.80 / 100K steps); idle/sleep not billed |
34
+ | **Limits** | 50 MB payloads; 2 GB/run; 10K steps ([Vercel World limits](https://vercel.com/docs/workflows/pricing)) | **1 MiB** step result & event payload; 1 GB state/instance; 10K steps (up to 25K) |
35
+
36
+ **What the limits mean in practice:** Cloudflare's 1 MiB cap on step results and event payloads is the tightest in this section — a single large model response or document can exceed it, pushing anything sizable into R2/KV indirection — and instance state is capped at 1 GB. The [Vercel World limits](https://vercel.com/docs/workflows/pricing) are 50 MB per payload and 2 GB of state per run.
37
+
38
+ ## Versioning: pinned vs. live code
39
+
40
+ Both engines replay, so changing code mid-run is the key hazard — and they take opposite approaches:
41
+
42
+ - **Cloudflare** does not pin a running instance to a code version. When an instance resumes (after a sleep, a wait, or a deploy), it runs against whatever code is currently deployed. Because step names act as the replay cache key, reordering, renaming, or inserting steps before already-completed ones can desync the replay of an in-flight instance. There is no patching API — just the documented "[Rules of Workflows](https://developers.cloudflare.com/workflows/build/rules-of-workflows/)" you must follow by hand.
43
+ - **Workflow SDK** pins each run to the immutable deployment that started it, so a deploy never disturbs in-flight runs. Evolving code is safe by default and upgrades are explicit.
44
+
45
+ ## Encryption and portability
46
+
47
+ Cloudflare encrypts Durable Object data at rest with Cloudflare-managed keys, but there is no application-level / end-to-end encryption and no customer-managed-key option — payloads are visible to the platform. The Workflow SDK encrypts each run's inputs, outputs, step I/O, and streams with a per-run AES-256-GCM key.
48
+
49
+ On portability, Cloudflare Workflows is the most locked-in of the tools in this section: the API and Durable-Object-bound state are Cloudflare-specific, so moving means a rewrite. The Workflow SDK is Apache-2.0 and its [World abstraction](/worlds/building-a-world) lets you run the same code on Vercel, on Postgres, or on a backend you build.
50
+
51
+ ## Where Cloudflare leads
52
+
53
+ Credit where due: Cloudflare's V8-isolate model gives **near-zero cold starts**, and code runs across its global Anycast network with no region selection. For latency-sensitive, globally-distributed workloads on Cloudflare's platform, that's a genuine strength. The Workflow SDK's performance depends on the World it runs on; on Vercel it benefits from Fluid Compute and a 100K concurrency ceiling, with multi-region rolling out.
54
+
55
+ ## Moving from Cloudflare Workflows
56
+
57
+ There's no automated migration skill for Cloudflare specifically, but the mapping is direct:
58
+
59
+ | Cloudflare Workflows | Workflow SDK |
60
+ | --- | --- |
61
+ | `class extends WorkflowEntrypoint` + `run(event, step)` | `"use workflow"` function started with `start()` |
62
+ | `step.do(name, cb)` | `"use step"` function called with `await` |
63
+ | `step.sleep` / `step.sleepUntil` | `sleep('1h')` / `sleep(date)` |
64
+ | `step.waitForEvent` | `createHook()` / `createWebhook()` |
65
+ | Per-step `retries` config | `maxRetries`, `RetryableError`, `FatalError` |
66
+ | `env.MY_WORKFLOW.create(...)` binding | `start(workflow, [args])` from your app |
67
+
68
+ Side effects that lived in `step.do` callbacks move into named `"use step"` functions; the orchestration becomes plain `await` / `if` / `Promise.all` instead of the `WorkflowEntrypoint` class.
69
+
70
+ ---
71
+ *Compiled from public documentation. Verify current Cloudflare Workflows limits and pricing against [developers.cloudflare.com/workflows](https://developers.cloudflare.com/workflows/). Not based on head-to-head benchmarks.*
@@ -0,0 +1,102 @@
1
+ ---
2
+ title: Workflow SDK vs Inngest
3
+ description: How the Workflow SDK compares to Inngest — event-driven durable functions that run on your own infrastructure over HTTP, with a concept-mapping migration guide.
4
+ type: conceptual
5
+ summary: Inngest is an event-driven durable-functions platform that invokes your code over HTTP and memoizes step results. The Workflow SDK co-locates orchestration and execution and replays from an event log.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/foundations/hooks
10
+ - /docs/foundations/streaming
11
+ - /docs/ai
12
+ ---
13
+
14
+ [Inngest](https://www.inngest.com) is a durable-functions platform with an **event-driven** core: functions trigger on events or cron, and Inngest invokes your code — running on your own infrastructure — one step at a time over HTTP, memoizing each step's result. It overlaps heavily with the Workflow SDK, with a different execution topology and a strong AI/agent story on both sides.
15
+
16
+ <Callout type="info">
17
+ **Choose the Workflow SDK** when you want orchestration and execution co-located (no per-step HTTP round-trips), deployment-pinned versioning, and a fully-supported open-source self-host path. **Choose Inngest** when an event-bus model fits your architecture and you want its mature flow-control suite (concurrency, throttling, debounce, batching, priority) out of the box.
18
+ </Callout>
19
+
20
+ ## At a glance
21
+
22
+ | | Workflow SDK | Inngest |
23
+ | --- | --- | --- |
24
+ | **Category** | Open-source durable-functions SDK | Durable functions on an event-driven platform |
25
+ | **Durability model** | Event log + deterministic replay | **Step-result memoization** (each `step.run` runs once; completed steps are skipped) — not whole-function replay |
26
+ | **Trigger model** | Direct `start(workflow, [args])` (import the function) | Event bus (`inngest.send`) + cron; loosely coupled publishers/consumers |
27
+ | **Where execution runs** | Orchestration + execution co-located on your platform | **Your code runs on your infra**; Inngest invokes it per step over HTTP (Serve) or a persistent worker connection (Connect, in public beta) |
28
+ | **Languages** | TypeScript / JS (Python beta) | TypeScript; Python & Go (production, pre-1.0) |
29
+ | **Versioning** | Runs pinned to immutable deployment | Tracked by step-ID hashes — hot-edit functions, but editing a step's logic under the **same ID** reuses the old memoized result for in-flight runs; rename the ID or route a new function by timestamp for rewrites |
30
+ | **AI & streaming** | `WorkflowAgent` in the AI SDK; native resumable streaming | Native AI SDK via `step.ai.wrap`; **AgentKit** multi-agent framework and durable **Realtime** (`step.realtime.publish`) + `useAgent` hook — both Developer Preview |
31
+ | **Security** | Zero-config per-run E2E encryption by default; platform security is per-World (the Vercel World inherits Vercel's security posture) | Runs on your infra; signed requests; first-party E2E encryption middleware (TS + Python); SOC 2 Type II, HIPAA add-on |
32
+ | **Portability** | Apache-2.0; World abstraction; **self-host supported** | Engine open source (SSPL); self-host via single Go binary + Postgres, but **self-hosting is community/best-effort** — no support SLA, and the `inngest start` binary is Beta (SaaS is the default) |
33
+ | **Pricing** | SDK free; pay your platform | Per-execution: billed for the run **plus each step plus retries**; Pro from $99/mo, then ~$50 per 1M executions |
34
+ | **Limits** | 50 MB payload; 2 GB/run; 10K steps ([Vercel World limits](https://vercel.com/docs/workflows/pricing)) | 1,000 steps/function; 4 MiB step payload; 32 MiB run state; runs up to 366 days |
35
+
36
+ **What the limits mean in practice:** Inngest's caps are restrictive for real long-running AI workloads. An agent loop spends steps on every model and tool call, so 1,000 steps per function goes quickly; a single large LLM response can approach the 4 MiB step-payload cap; and an accumulated conversation or context easily outgrows 32 MiB of run state. The [Vercel World limits](https://vercel.com/docs/workflows/pricing) are 50 MB per payload and 2 GB of state per run.
37
+
38
+ ## Topology: co-located vs. invoked-over-HTTP
39
+
40
+ Inngest's engine lives outside your code and calls your functions step-by-step over HTTP (or a Connect worker). That keeps your code on your own infra (a portability and data-locality plus), but adds a network round-trip per step — relevant for workflows with many small sequential steps. The Workflow SDK co-locates orchestration and execution on one platform, so steps don't pay a per-step HTTP hop.
41
+
42
+ Triggering differs too: Inngest is event-driven (publishers `send` events; functions subscribe), which is great for loosely-coupled fan-out. The Workflow SDK's `start()` imports the workflow function directly — tighter coupling, stronger type safety. For event-bus-style fan-out, wrap `start()` in a shared publisher.
43
+
44
+ ## Versioning
45
+
46
+ Inngest doesn't use version numbers; it keys state by **step-ID hash**, so you can edit functions while runs are in flight. The catch: if you change the logic *inside* a step but keep the same ID, in-flight runs that already completed that step silently reuse the **old** memoized result — only new runs see the change. To force re-execution you rename the step ID, and for incompatible rewrites the recommended pattern is a new function with timestamp-based event routing.
47
+
48
+ The Workflow SDK pins each run to its immutable deployment, so in-flight runs always finish on the exact code they started with, and upgrades are explicit — no per-step-ID reasoning required.
49
+
50
+ ## AI agents
51
+
52
+ Both are strong here. Inngest offers `step.ai.wrap()` (wrap Vercel AI SDK calls as durable steps), **AgentKit** (a multi-agent framework with MCP tools), and durable **Realtime** streaming with a `useAgent` React hook — though AgentKit and Realtime are both Developer Preview. The Workflow SDK offers `WorkflowAgent` directly inside the AI SDK and native [resumable streaming](/docs/ai/resumable-streams). If you're already event-driven and want a batteries-included agent framework, AgentKit is compelling; if you want the agent loop to *be* a durable workflow in your app with streaming built into the runtime, the Workflow SDK fits.
53
+
54
+ ## Migrating from Inngest
55
+
56
+ | Inngest | Workflow SDK | Note |
57
+ | --- | --- | --- |
58
+ | `inngest.createFunction()` | `"use workflow"` function started with `start()` | No factory or event binding. |
59
+ | `step.run()` | `"use step"` function | Named async function with Node.js access. |
60
+ | `step.sleep()` / `step.sleepUntil()` | `sleep('5m')` / `sleep(date)` | Import from `workflow`. |
61
+ | `step.waitForEvent()` | `createHook()` / `createWebhook()` | Token encodes the routing; no event schema. |
62
+ | `step.invoke()` | `"use step"` wrappers around `start()` / `getRun()` | Spawn a child run. |
63
+ | `inngest.send()` / event triggers | `start()` from your app boundary | Start workflows directly. |
64
+ | Retry config (`retries`) | `maxRetries`, `RetryableError`, `FatalError` | Retries live at the step boundary. |
65
+ | `step.realtime.publish()` / Realtime | `getWritable()` / named streams | Clients read from the stream. |
66
+
67
+ The `createFunction` factory collapses into a plain exported function:
68
+
69
+ ```typescript title="workflows/order.ts"
70
+ export async function processOrder(orderId: string) {
71
+ 'use workflow'; // [!code highlight]
72
+ const order = await loadOrder(orderId);
73
+ return { orderId: order.id, status: 'completed' };
74
+ }
75
+
76
+ async function loadOrder(orderId: string) {
77
+ 'use step'; // [!code highlight]
78
+ const res = await fetch(`https://example.com/api/orders/${orderId}`);
79
+ return res.json() as Promise<{ id: string }>;
80
+ }
81
+ ```
82
+
83
+ <Callout type="info">
84
+ Install the migration skill to translate an Inngest app automatically:
85
+
86
+ ```bash
87
+ npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk
88
+ ```
89
+ </Callout>
90
+
91
+ ### Inngest features without a direct Workflow SDK equivalent
92
+
93
+ Each row is an Inngest capability the Workflow SDK does not replicate one-to-one, paired with how to cover it on the Workflow SDK side:
94
+
95
+ | Inngest feature | How to cover it with the Workflow SDK |
96
+ | --- | --- |
97
+ | Flow control (concurrency, throttling, debounce, rate limiting, batching, priority) | No direct function-level analog; enforce limits inside steps or debounce at the publisher before `start()` |
98
+ | Cron / scheduled functions | Trigger from Vercel Cron or a system cron calling `start()` |
99
+ | Event-bus fan-out by name match | Replace with explicit `start()` calls per target workflow |
100
+
101
+ ---
102
+ *Compiled from public documentation. Inngest tier names and pricing vary across sources; verify against [inngest.com/pricing](https://www.inngest.com/pricing). Not based on head-to-head benchmarks.*
@@ -0,0 +1,123 @@
1
+ ---
2
+ title: Workflow SDK vs Temporal
3
+ description: How the Workflow SDK compares to Temporal — execution model, where workers run, versioning, AI agents, pricing, and a concept-mapping migration guide.
4
+ type: conceptual
5
+ summary: Temporal is a mature, language-agnostic durable-execution platform where you run the workers. The Workflow SDK runs in your existing app and pins runs to immutable deployments.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/foundations/hooks
10
+ - /docs/foundations/streaming
11
+ - /docs/ai
12
+ - /worlds/vercel
13
+ ---
14
+
15
+ [Temporal](https://temporal.io) is the most mature durable-execution platform — battle-tested at large scale, with seven language SDKs. It and the Workflow SDK share the same core idea (durable orchestration via event-sourced replay), so the real differences are operational: **where your code runs, how you version it, and how it streams to clients.**
16
+
17
+ <Callout type="info">
18
+ **Choose the Workflow SDK** when you want durable execution inside your existing TypeScript app with nothing extra to operate, deployment-pinned versioning, and native streaming for AI apps. **Choose Temporal** when you need polyglot SDKs (Go/Java/etc.), want a self-hostable control plane you fully own, or are standardizing a large org on one orchestration backend across many languages.
19
+ </Callout>
20
+
21
+ ## At a glance
22
+
23
+ | | Workflow SDK | Temporal |
24
+ | --- | --- | --- |
25
+ | **Category** | Open-source durable-functions SDK; managed on Vercel or self-hosted | Durable-execution platform; Temporal Cloud or self-hosted cluster |
26
+ | **Durability model** | Event log + deterministic replay (`"use workflow"` orchestrators, `"use step"` functions) | Event-sourced replay (Workflows + Activities). Same model — `"use workflow"` ≈ Workflow, `"use step"` ≈ Activity |
27
+ | **Languages** | TypeScript / JS (Python beta) | Go, Java, TypeScript, Python, .NET, PHP, Ruby (7 SDKs) |
28
+ | **Where execution runs** | Orchestration + execution + observability co-located on your platform; private networking and E2E encryption out of the box on Vercel | **You run and scale your own Workers.** Temporal Cloud hosts orchestration only; workers connect outbound over the public internet (PrivateLink optional) |
29
+ | **Versioning** | Runs pinned to their immutable deployment — safe by default; opt-in `deploymentId: 'latest'` to upgrade | Editing workflow code can break in-flight runs (non-determinism errors); evolve safely via patch APIs or Worker Versioning (keep old worker fleets draining) |
30
+ | **AI SDK & agents** | `WorkflowAgent` ships in the AI SDK; durable agent loop; **native resumable streaming** (`getWritable`/`getReadable`, `WorkflowChatTransport`) | First-party `@temporalio/ai-sdk` and "Workflow Streams" — both **Public Preview**; streaming rides on Signals/Updates (batched, history-bound) |
31
+ | **Security** | Zero-config per-run AES-256-GCM E2E encryption by default; platform security is per-World (the Vercel World inherits Vercel's security posture) | Workers run your code on your infra (never enters Temporal's plane); client-side E2E via a Codec Server you operate. Cloud: SOC 2 II, HIPAA, GDPR |
32
+ | **Performance** | No-penalty resume; serverless scale-to-zero (true suspension); up to 100K concurrency on Vercel | Self-managed workers are long-running; Cloud namespace default 500 actions/sec (auto-scales) |
33
+ | **Portability** | Apache-2.0 SDK; World abstraction swaps storage/queue/streams independently | MIT server; pluggable persistence (Cassandra/Postgres/MySQL), but an opinionated monolithic backend you run or pay for |
34
+ | **Pricing** | SDK free; pay your platform (Vercel: events + data) or just your infra if self-hosted | Self-host = free software; Temporal Cloud bills per Action (from $50/M) + storage |
35
+ | **Limits** | No run/sleep cap; 10K steps, 50 MB payload, 2 GB/run ([Vercel World limits](https://vercel.com/docs/workflows/pricing)) | No run cap (Continue-As-New for long histories); event history capped at 51,200 events / 50 MB; 2 MB payloads |
36
+
37
+ **What the limits mean in practice:** Temporal caps payloads at 2 MB and event history at 51,200 events, which binds quickly for AI workloads — a large model context, tool transcript, or embedding batch routinely exceeds 2 MB, forcing external blob storage and claim-check plumbing, and long agent loops must be split with Continue-As-New before the history fills. The [Vercel World limits](https://vercel.com/docs/workflows/pricing) (50 MB payloads, 2 GB of state per run, no run or sleep caps) leave room to keep full contexts in the run itself.
38
+
39
+ ## The biggest difference: what you operate
40
+
41
+ Temporal Cloud manages the durable engine, but **you still build, deploy, and scale a fleet of Workers** that poll task queues and run your Workflow and Activity code. Those workers connect *out* to Temporal Cloud, typically over the public internet (AWS PrivateLink / GCP Private Service Connect are available as same-region options). Readable observability requires you to stand up a **Codec Server** so the Web UI can decrypt payloads your data converter encrypted.
42
+
43
+ With the Workflow SDK on Vercel, orchestration, execution, and observability are co-located on one platform with internal networking, and per-run E2E encryption is on by default with no codec server to run. There are no workers, task queues, or a control plane to operate. (Self-hosting via the [Postgres World](/worlds/postgres) is the closest analog to running your own Temporal cluster.)
44
+
45
+ ## Versioning
46
+
47
+ This is where the two differ most in day-to-day risk. Because both replay code against history, *changing* workflow code mid-flight is the hazard.
48
+
49
+ - **Temporal:** simply editing a workflow can produce a non-determinism error that breaks or stalls open executions. You evolve safely with **patch APIs** (`patched()` / `GetVersion()`, which accumulate branch cruft) or **Worker Versioning** (Build IDs / Worker Deployments pin workflows to a build and keep the old worker fleet running until it drains). It works, but the burden is on you for every long-running workflow.
50
+ - **Workflow SDK:** runs are **pinned to the immutable deployment that started them**. Shipping new code never touches in-flight runs — they keep replaying against the exact code they began on. Upgrading a run is explicit and opt-in (start it with `deploymentId: 'latest'`, or self-restart at a checkpoint). Safe by default, no patch branches, no draining worker fleets.
51
+
52
+ ## AI agents and streaming
53
+
54
+ Both target AI agents, but the integration depth differs. The Workflow SDK's `WorkflowAgent` is a first-class construct **inside the AI SDK** (`@ai-sdk/workflow`): the agent loop becomes a durable workflow, each tool `execute` marked `"use step"` is an auto-retried durable step, and partial output streams through [durable, resumable streams](/docs/ai/resumable-streams) that survive reconnects and cold starts.
55
+
56
+ Temporal ships a first-party `@temporalio/ai-sdk` plugin and a "Workflow Streams" library, but both are **Public Preview**, and streaming is built on Signals/Updates — every chunk is written to history, so it's batched rather than per-token.
57
+
58
+ ## Migrating from Temporal
59
+
60
+ The model maps closely. Keep your orchestration logic; drop the workers, task queues, and activity modules.
61
+
62
+ | Temporal | Workflow SDK | Note |
63
+ | --- | --- | --- |
64
+ | Workflow Definition / Execution | `"use workflow"` function started with `start()` | Orchestration stays in the workflow function. |
65
+ | Activity | `"use step"` function | Side effects and Node.js access live in steps. |
66
+ | Worker + Task Queue | Managed execution | No worker fleet or polling loop to operate. |
67
+ | Signal | `createHook()` / `createWebhook()` | Hooks for typed resume signals; webhooks for HTTP callbacks. |
68
+ | Query | `getWritable({ namespace: 'status' })` stream | Stream status durably; clients read the stream instead of polling. |
69
+ | Child Workflow | `"use step"` wrapper around `start()` / `getRun()` | Return the `Run` object so observability can deep-link. |
70
+ | Activity retry policy | `maxRetries`, `RetryableError`, `FatalError` | Retries live at the step boundary. |
71
+ | Event History | Workflow event log / run timeline | Same durable replay; built-in observability UI. |
72
+
73
+ A minimal translation — the orchestrator loses `proxyActivities` and becomes plain TypeScript:
74
+
75
+ ```typescript title="workflows/order.ts"
76
+ export async function processOrder(orderId: string) {
77
+ 'use workflow'; // [!code highlight]
78
+ await chargePayment(orderId);
79
+ return { orderId, status: 'completed' };
80
+ }
81
+
82
+ async function chargePayment(orderId: string) {
83
+ 'use step'; // [!code highlight]
84
+ await fetch(`https://example.com/api/orders/${orderId}/charge`, { method: 'POST' });
85
+ }
86
+ ```
87
+
88
+ Signals become hooks — one `createHook()` + `await` replaces a signal definition, handler, and `condition()` guard:
89
+
90
+ ```typescript title="workflows/refund.ts"
91
+ import { createHook } from 'workflow';
92
+
93
+ export async function refundWorkflow(refundId: string) {
94
+ 'use workflow';
95
+ using approval = createHook<{ approved: boolean }>({
96
+ token: `refund:${refundId}:approval`, // [!code highlight]
97
+ });
98
+ const { approved } = await approval; // suspends durably until resumed
99
+ return { refundId, approved };
100
+ }
101
+ ```
102
+
103
+ <Callout type="info">
104
+ Install the migration skill to translate a Temporal app automatically:
105
+
106
+ ```bash
107
+ npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk
108
+ ```
109
+ </Callout>
110
+
111
+ ### Temporal features without a direct Workflow SDK equivalent
112
+
113
+ Each row is a Temporal capability the Workflow SDK does not replicate one-to-one, paired with how to cover it on the Workflow SDK side:
114
+
115
+ | Temporal feature | How to cover it with the Workflow SDK |
116
+ | --- | --- |
117
+ | Search attributes / visibility queries | Filter runs by status and timestamps via `getRun()` and the observability UI |
118
+ | Per-activity timeouts (`startToCloseTimeout`, etc.) | Enforce deadlines inside a step with `AbortSignal.timeout(ms)`, or wrap a call in `Promise.race(step(), sleep('5m'))` |
119
+ | Rich retry policy (`backoffCoefficient`, `nonRetryableErrorTypes`) | Only `maxRetries` is configurable; classify with `RetryableError` / `FatalError` and set delay via `new RetryableError(msg, { retryAfter: '5s' })` |
120
+ | Polyglot workers | The Workflow SDK is TypeScript-first (Python in beta); for Go/Java/etc. in the same orchestrator, Temporal remains the better fit |
121
+
122
+ ---
123
+ *Compiled from public documentation. Verify current Temporal pricing, limits, and preview-feature status against [temporal.io/docs](https://docs.temporal.io). Not based on head-to-head benchmarks.*
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: Workflow SDK vs trigger.dev
3
+ description: How the Workflow SDK compares to trigger.dev — deterministic event-log replay versus CRIU process checkpoint/restore, plus a concept-mapping migration guide.
4
+ type: conceptual
5
+ summary: trigger.dev achieves durability by snapshotting the process (CRIU), so code has no determinism constraints. The Workflow SDK uses event-log replay and runs in your existing app.
6
+ prerequisites:
7
+ - /docs/foundations/workflows-and-steps
8
+ related:
9
+ - /docs/foundations/errors-and-retries
10
+ - /docs/foundations/streaming
11
+ - /docs/ai
12
+ ---
13
+
14
+ [trigger.dev](https://trigger.dev) is an open-source, TypeScript-first durable task platform. Its defining trait is *how* it achieves durability: instead of replaying code, it **snapshots the whole process** (CRIU checkpoint/restore) at each wait point and restores it later. That single design choice drives most of the differences with the Workflow SDK.
15
+
16
+ <Callout type="info">
17
+ **Choose the Workflow SDK** when you want durable orchestration that runs in your existing app, a portable open-source backend you can fully self-host, TypeScript *and* Python, and broad framework support. **Choose trigger.dev** when you want a managed task platform with no determinism constraints (code runs as-is), and you're TypeScript-only.
18
+ </Callout>
19
+
20
+ ## At a glance
21
+
22
+ | | Workflow SDK | trigger.dev |
23
+ | --- | --- | --- |
24
+ | **Category** | Open-source durable-functions SDK that runs in your app | Durable task platform with its own runtime (Cloud or self-hosted) |
25
+ | **Durability model** | Event log + **deterministic replay** (workflow body must be deterministic) | **Process checkpoint/restore (CRIU)** — snapshots memory/CPU/FDs; **no determinism constraints**, code runs as-is |
26
+ | **Authoring** | `"use workflow"` / `"use step"` in your existing app | `task()` / `schemaTask()` deployed to trigger.dev as a separate target (Docker image) |
27
+ | **Languages** | TypeScript / JS (Python beta) | **TypeScript / JS only** |
28
+ | **Where it runs** | Co-located with your app (Vercel managed or self-host) | trigger.dev's run engine (isolated containers) |
29
+ | **Versioning** | Runs pinned to immutable deployment — safe by default | **Atomic versioning** — runs lock to their deploy version; new deploys never touch in-flight runs (same safety property) |
30
+ | **AI & streaming** | `WorkflowAgent` in the AI SDK; native resumable streaming | First-class: AI SDK tools, native `useChat` transport, resumable Realtime, durable multi-turn Sessions, HITL via `wait.forToken` |
31
+ | **Concurrency control** | Enforce in steps / at the publisher | First-class queues + concurrency keys |
32
+ | **Portability** | Apache-2.0; World abstraction; runs anywhere Node runs | Apache-2.0; self-host on Docker/K8s — but CRIU needs a compatible host (heavier than plain Docker); TS-only |
33
+ | **Pricing** | SDK free; pay your platform | Cloud: compute-seconds + per-run ($0.0000338/s Small + $0.000025/run); no charge while checkpointed |
34
+ | **Limits** | 50 MB payload; 2 GB/run; no duration cap ([Vercel World limits](https://vercel.com/docs/workflows/pricing)) | 3 MB payload / 10 MB output; 14-day max run TTL; CPU-time-based max duration |
35
+
36
+ **What the limits mean in practice:** trigger.dev caps task payloads at 3 MB and outputs at 10 MB — large model contexts and transcripts need external storage — and the 14-day run TTL means human-in-the-loop flows that wait longer than two weeks can't complete in one run. The [Vercel World limits](https://vercel.com/docs/workflows/pricing) are 50 MB payloads, 2 GB of state per run, and no run-duration cap.
37
+
38
+ ## The core difference: checkpoint/restore vs. replay
39
+
40
+ trigger.dev freezes the entire OS process with CRIU when a task hits a wait point, then restores it later — so there's **no replay and no determinism rule**: you can call `Date.now()` or `Math.random()` anywhere, and prior steps don't re-execute. The cost is an execution model that requires CRIU-capable infrastructure (which makes self-hosting heavier than a plain container) and runs on trigger.dev's runtime as a separate deploy target.
41
+
42
+ The Workflow SDK reconstructs state by **replaying the workflow function** against its event log. That requires the workflow body to be deterministic (side effects go in `"use step"` functions), but it runs inside your existing app and deployment with no special host requirements, and the [World abstraction](/worlds/building-a-world) lets you swap the storage/queue/stream layers.
43
+
44
+ Notably, **both pin runs to a version** so deploys never corrupt in-flight work — trigger.dev via atomic version-locking, the Workflow SDK via immutable-deployment pinning.
45
+
46
+ ## AI agents
47
+
48
+ Both invest heavily in AI. trigger.dev offers AI SDK tool wrapping, a native `useChat` transport over its Realtime layer, resumable streaming, and durable multi-turn Sessions. The Workflow SDK offers `WorkflowAgent` directly inside the AI SDK plus native [resumable streaming](/docs/ai/resumable-streams). Both support human-in-the-loop (trigger.dev's `wait.forToken`, the Workflow SDK's hooks). The deciding factors are usually language (trigger.dev is TS-only; the Workflow SDK adds Python) and whether you want the agent to run in your app vs. on a dedicated platform.
49
+
50
+ ## Migrating from trigger.dev
51
+
52
+ | trigger.dev | Workflow SDK | Note |
53
+ | --- | --- | --- |
54
+ | `task({ id, run })` | `"use workflow"` function started with `start()` | No factory or id registry. |
55
+ | `schemaTask({ schema, run })` | Typed function + `"use workflow"` | Validate inputs at the call site. |
56
+ | Inline `run` body | `"use step"` functions | Side effects move into named steps. |
57
+ | `wait.for` / `wait.until` | `sleep('5m')` / `sleep(date)` | Import from `workflow`. |
58
+ | `wait.forToken({ timeout })` | `createHook()` + `Promise.race` with `sleep()` | Hooks carry a typed token. |
59
+ | `triggerAndWait()` | `"use step"` wrappers around `start()` / `getRun()` | Spawn + collect. |
60
+ | `batch.triggerAndWait()` | `Promise.all` over collected `Run` handles | Standard concurrency. |
61
+ | `metadata.stream()` / Realtime | `getWritable()` / named streams | Clients read from the stream. |
62
+ | `AbortTaskRunError` | `FatalError` | Stops retries immediately. |
63
+
64
+ The `task()` factory collapses into a plain function — and because the workflow body is replayed, move side effects into steps:
65
+
66
+ ```typescript title="workflows/order.ts"
67
+ export async function processOrder(orderId: string) {
68
+ 'use workflow'; // [!code highlight]
69
+ const order = await loadOrder(orderId);
70
+ return { orderId: order.id, status: 'completed' };
71
+ }
72
+
73
+ async function loadOrder(orderId: string) {
74
+ 'use step'; // [!code highlight]
75
+ const res = await fetch(`https://example.com/api/orders/${orderId}`);
76
+ return res.json() as Promise<{ id: string }>;
77
+ }
78
+ ```
79
+
80
+ <Callout type="warn">
81
+ trigger.dev's `run` body has full Node.js access. The Workflow SDK's `"use workflow"` body runs in a sandboxed VM — side effects (`fetch`, `Date.now()`, `Math.random()`, DB access) must live inside `"use step"` functions. Orchestration stays in the workflow body.
82
+ </Callout>
83
+
84
+ <Callout type="info">
85
+ Install the migration skill to translate a trigger.dev app automatically:
86
+
87
+ ```bash
88
+ npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk
89
+ ```
90
+ </Callout>
91
+
92
+ ### trigger.dev features without a direct Workflow SDK equivalent
93
+
94
+ Each row is a trigger.dev capability the Workflow SDK does not replicate one-to-one, paired with how to cover it on the Workflow SDK side:
95
+
96
+ | trigger.dev feature | How to cover it with the Workflow SDK |
97
+ | --- | --- |
98
+ | Concurrency keys / queue concurrency limits | Enforce limits inside steps or debounce at the publisher |
99
+ | `schedules.task()` / cron | Trigger from Vercel Cron or a system cron calling `start()` |
100
+ | `machine` presets / custom images | Function resources are per-deployment (configured via your hosting platform) |
101
+
102
+ ---
103
+ *Compiled from public documentation. Verify current trigger.dev limits and pricing against [trigger.dev/docs](https://trigger.dev/docs). Not based on head-to-head benchmarks.*
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: Build and Diagnostics
3
+ description: Build-time environment variables for manifests, source maps, and development diagnostics.
4
+ type: reference
5
+ summary: Configure generated bundles and build-time diagnostics.
6
+ related:
7
+ - /docs/configuration/framework-options
8
+ - /docs/api-reference/workflow-next/with-workflow
9
+ ---
10
+
11
+ Build and diagnostics variables are read by the compiler, builders, and framework integrations when your app is built or when the dev server starts.
12
+
13
+ ## Source maps
14
+
15
+ ### `WORKFLOW_SOURCEMAP`
16
+
17
+ - Framework option: `sourcemap` where supported
18
+ - Default: `inline` in development, `false` in production
19
+ - Controls source maps for generated workflow bundles.
20
+ - Explicit framework config wins over this environment variable.
21
+
22
+ Accepted values:
23
+
24
+ - `true`, `inline`, or `1` - append an inline base64 source map to each generated bundle.
25
+ - `linked` - write a `.map` file and add a `sourceMappingURL` comment.
26
+ - `external` - write a `.map` file without adding the comment.
27
+ - `both` - emit inline and external source maps.
28
+ - `false` or `0` - omit source maps.
29
+
30
+ ### `WORKFLOW_EMIT_SOURCEMAPS_FOR_DEBUGGING`
31
+
32
+ - Default: disabled
33
+ - Legacy source-map toggle kept for compatibility.
34
+ - Only affects the final workflow wrapper and webhook bundle.
35
+ - Prefer `WORKFLOW_SOURCEMAP` or a framework `sourcemap` option.
36
+
37
+ ## Manifests
38
+
39
+ ### `WORKFLOW_PUBLIC_MANIFEST`
40
+
41
+ - Default: disabled
42
+ - Set `1` to expose the workflow manifest at `/.well-known/workflow/v1/manifest.json`.
43
+ - Useful for e2e tests and tools that need to discover workflows over HTTP.
44
+
45
+ ## Discovery
46
+
47
+ ### `WORKFLOW_DISCOVER_NODE_MODULES`
48
+
49
+ - Framework option: `discoverWorkflowsInNodeModules` where supported
50
+ - Default: enabled
51
+ - Controls whether workflow discovery descends into `node_modules`. By default, dependencies that declare a `workflow`/`@workflow/*` dependency can ship `"use workflow"`/`"use step"` files that are discovered and compiled into your app's bundles.
52
+ - Set `0` or `false` to opt out — imports from your application code that resolve into `node_modules` are not followed, so the build never reads, scans, or descends into dependency file graphs. This skips the cost of scanning `node_modules` and stops third-party workflow/step/serde code from being discovered. Useful when a dependency ships workflow code you don't want compiled into your app, or trips discovery with directive strings you don't intend to run.
53
+ - The SDK's own runtime serde classes (e.g. `Run`) stay registered — they are reached through a seeded entry point, and imports *within* `node_modules` are still followed.
54
+ - Explicit framework config wins over this environment variable.
55
+
56
+ ## Development diagnostics
57
+
58
+ ### `WORKFLOW_DEV_HMR_LOGS`
59
+
60
+ - Default: disabled
61
+ - Set `1` to log workflow rebuild activity during `next dev`.
62
+ - Useful for diagnosing watch and HMR issues.
63
+
64
+ ### `WORKFLOW_DEV_WATCH_IGNORED_PATHS`
65
+
66
+ - Default: unset
67
+ - Dev-mode only (`next dev`). Comma-separated list of path fragments the file watcher should never watch, in addition to the built-in ignores and your project's `.gitignore`.
68
+ - Each entry is matched as a substring of the absolute path (e.g. `/fixtures/,/generated/`).
69
+ - The watcher already respects `.gitignore` (walking from the app directory up to the workspace root). Use this variable only for large directories you cannot or do not want to add to `.gitignore`.
70
+ - Useful when a project has thousands of non-ignored directories and `next dev` fails with `EMFILE: too many open files, watch`.