workflow 5.0.0-beta.9 → 5.0.0

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 (263) hide show
  1. package/README.md +68 -23
  2. package/dist/api-workflow.d.ts +3 -1
  3. package/dist/api-workflow.d.ts.map +1 -1
  4. package/dist/api-workflow.js +2 -1
  5. package/dist/api.d.ts +5 -4
  6. package/dist/api.d.ts.map +1 -1
  7. package/dist/api.js +6 -7
  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 +4 -4
  12. package/dist/internal/builtins.js +6 -6
  13. package/dist/internal/errors.d.ts +1 -1
  14. package/dist/internal/errors.d.ts.map +1 -1
  15. package/dist/internal/errors.js +2 -2
  16. package/dist/nest-builder.d.ts +2 -0
  17. package/dist/nest-builder.d.ts.map +1 -0
  18. package/dist/nest-builder.js +2 -0
  19. package/dist/nest-vercel-builder.d.ts +2 -0
  20. package/dist/nest-vercel-builder.d.ts.map +1 -0
  21. package/dist/nest-vercel-builder.js +2 -0
  22. package/dist/runtime.d.ts +2 -1
  23. package/dist/runtime.d.ts.map +1 -1
  24. package/dist/runtime.js +4 -1
  25. package/docs/advanced/dynamic-workflows.mdx +224 -0
  26. package/docs/ai/chat-session-modeling.mdx +176 -422
  27. package/docs/ai/defining-tools.mdx +6 -7
  28. package/docs/ai/human-in-the-loop.mdx +11 -11
  29. package/docs/ai/index.mdx +67 -72
  30. package/docs/ai/message-queueing.mdx +71 -110
  31. package/docs/ai/meta.json +1 -0
  32. package/docs/ai/resumable-streams.mdx +40 -28
  33. package/docs/ai/sleep-and-delays.mdx +10 -10
  34. package/docs/ai/streaming-updates-from-tools.mdx +6 -6
  35. package/docs/api-reference/index.mdx +25 -1
  36. package/docs/api-reference/meta.json +8 -0
  37. package/docs/api-reference/vitest/index.mdx +68 -15
  38. package/docs/api-reference/workflow/create-hook.mdx +166 -10
  39. package/docs/api-reference/workflow/create-webhook.mdx +16 -15
  40. package/docs/api-reference/workflow/define-hook.mdx +37 -33
  41. package/docs/api-reference/workflow/fatal-error.mdx +30 -8
  42. package/docs/api-reference/workflow/fetch.mdx +14 -10
  43. package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
  44. package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
  45. package/docs/api-reference/workflow/get-writable.mdx +7 -7
  46. package/docs/api-reference/workflow/index.mdx +3 -3
  47. package/docs/api-reference/workflow/retryable-error.mdx +1 -1
  48. package/docs/api-reference/workflow/set-attributes.mdx +63 -0
  49. package/docs/api-reference/workflow/sleep.mdx +4 -4
  50. package/docs/api-reference/workflow-ai/durable-agent.mdx +63 -101
  51. package/docs/api-reference/workflow-ai/index.mdx +5 -5
  52. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +67 -24
  53. package/docs/api-reference/workflow-api/get-hook-by-token.mdx +28 -12
  54. package/docs/api-reference/workflow-api/get-run.mdx +43 -8
  55. package/docs/api-reference/workflow-api/index.mdx +8 -9
  56. package/docs/api-reference/workflow-api/register-lifecycle-hooks.mdx +87 -0
  57. package/docs/api-reference/workflow-api/resume-hook.mdx +73 -12
  58. package/docs/api-reference/workflow-api/resume-webhook.mdx +11 -9
  59. package/docs/api-reference/workflow-api/start.mdx +107 -12
  60. package/docs/api-reference/workflow-astro/index.mdx +18 -0
  61. package/docs/api-reference/workflow-astro/meta.json +4 -0
  62. package/docs/api-reference/workflow-astro/workflow.mdx +45 -0
  63. package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
  64. package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +60 -0
  65. package/docs/api-reference/workflow-errors/hook-force-claimed-error.mdx +70 -0
  66. package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
  67. package/docs/api-reference/workflow-errors/index.mdx +91 -0
  68. package/docs/api-reference/workflow-errors/meta.json +7 -0
  69. package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +68 -0
  70. package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
  71. package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +58 -0
  72. package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
  73. package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
  74. package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
  75. package/docs/api-reference/workflow-errors/workflow-error.mdx +52 -0
  76. package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
  77. package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +13 -6
  78. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +12 -5
  79. package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +58 -0
  80. package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
  81. package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +58 -0
  82. package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
  83. package/docs/api-reference/workflow-globals.mdx +15 -11
  84. package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +37 -0
  85. package/docs/api-reference/workflow-nest/index.mdx +31 -0
  86. package/docs/api-reference/workflow-nest/meta.json +9 -0
  87. package/docs/api-reference/workflow-nest/nest-local-builder.mdx +64 -0
  88. package/docs/api-reference/workflow-nest/workflow-controller.mdx +46 -0
  89. package/docs/api-reference/workflow-nest/workflow-module.mdx +134 -0
  90. package/docs/api-reference/workflow-next/with-workflow.mdx +39 -17
  91. package/docs/api-reference/workflow-nitro/index.mdx +60 -0
  92. package/docs/api-reference/workflow-nuxt/index.mdx +48 -0
  93. package/docs/api-reference/workflow-observability/hydrate-data.mdx +35 -0
  94. package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +62 -0
  95. package/docs/api-reference/workflow-observability/index.mdx +62 -0
  96. package/docs/api-reference/workflow-observability/meta.json +11 -0
  97. package/docs/api-reference/workflow-observability/observability-revivers.mdx +50 -0
  98. package/docs/api-reference/workflow-observability/parse-class-name.mdx +41 -0
  99. package/docs/api-reference/workflow-observability/parse-step-name.mdx +40 -0
  100. package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +55 -0
  101. package/docs/api-reference/workflow-runtime/create-world.mdx +39 -0
  102. package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +44 -0
  103. package/docs/api-reference/{workflow-api → workflow-runtime}/get-world.mdx +11 -14
  104. package/docs/api-reference/workflow-runtime/health-check.mdx +51 -0
  105. package/docs/api-reference/workflow-runtime/index.mdx +41 -0
  106. package/docs/api-reference/workflow-runtime/meta.json +12 -0
  107. package/docs/api-reference/workflow-runtime/set-world.mdx +51 -0
  108. package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +43 -0
  109. package/docs/api-reference/workflow-runtime/world/analytics.mdx +315 -0
  110. package/docs/api-reference/workflow-runtime/world/index.mdx +60 -0
  111. package/docs/api-reference/workflow-runtime/world/meta.json +4 -0
  112. package/docs/api-reference/workflow-runtime/world/queue.mdx +88 -0
  113. package/docs/api-reference/{workflow-api → workflow-runtime}/world/storage.mdx +104 -35
  114. package/docs/api-reference/{workflow-api → workflow-runtime}/world/streams.mdx +8 -8
  115. package/docs/api-reference/workflow-serde/index.mdx +1 -2
  116. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +3 -4
  117. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +8 -8
  118. package/docs/api-reference/workflow-sveltekit/index.mdx +18 -0
  119. package/docs/api-reference/workflow-sveltekit/meta.json +4 -0
  120. package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +42 -0
  121. package/docs/api-reference/workflow-vite/index.mdx +18 -0
  122. package/docs/api-reference/workflow-vite/meta.json +4 -0
  123. package/docs/api-reference/workflow-vite/workflow.mdx +48 -0
  124. package/docs/changelog/attributes-mvp.mdx +53 -41
  125. package/docs/changelog/batched-event-writes.mdx +79 -0
  126. package/docs/changelog/eager-processing.mdx +110 -436
  127. package/docs/changelog/index.mdx +4 -2
  128. package/docs/changelog/lazy-event-creation.md +127 -0
  129. package/docs/changelog/lazy-hook-resume.mdx +78 -0
  130. package/docs/changelog/meta.json +11 -1
  131. package/docs/changelog/resilient-resume.mdx +32 -0
  132. package/docs/changelog/resilient-start.mdx +33 -285
  133. package/docs/changelog/step-message-ownership.mdx +360 -0
  134. package/docs/changelog/turbo-mode.md +87 -0
  135. package/docs/comparisons/index.mdx +66 -0
  136. package/docs/comparisons/meta.json +11 -0
  137. package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +55 -0
  138. package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +111 -0
  139. package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +71 -0
  140. package/docs/comparisons/workflow-sdk-vs-inngest.mdx +102 -0
  141. package/docs/comparisons/workflow-sdk-vs-temporal.mdx +123 -0
  142. package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +104 -0
  143. package/docs/configuration/build-and-diagnostics.mdx +79 -0
  144. package/docs/configuration/cli-and-web-ui.mdx +241 -0
  145. package/docs/configuration/framework-options.mdx +165 -0
  146. package/docs/configuration/index.mdx +32 -0
  147. package/docs/configuration/meta.json +12 -0
  148. package/docs/configuration/runtime-tuning.mdx +399 -0
  149. package/docs/configuration/worlds.mdx +315 -0
  150. package/docs/cookbook/advanced/child-workflows.mdx +33 -25
  151. package/docs/cookbook/advanced/publishing-libraries.mdx +65 -56
  152. package/docs/cookbook/advanced/serializable-steps.mdx +48 -68
  153. package/docs/cookbook/advanced/upgrading-workflows.mdx +35 -31
  154. package/docs/cookbook/agent-patterns/agent-cancellation.mdx +78 -60
  155. package/docs/cookbook/agent-patterns/durable-agent.mdx +23 -135
  156. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +180 -195
  157. package/docs/cookbook/common-patterns/batching.mdx +20 -14
  158. package/docs/cookbook/common-patterns/idempotency.mdx +41 -53
  159. package/docs/cookbook/common-patterns/rate-limiting.mdx +8 -4
  160. package/docs/cookbook/common-patterns/saga.mdx +23 -19
  161. package/docs/cookbook/common-patterns/scheduling.mdx +30 -22
  162. package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +29 -25
  163. package/docs/cookbook/common-patterns/timeouts.mdx +26 -21
  164. package/docs/cookbook/common-patterns/webhooks.mdx +10 -6
  165. package/docs/cookbook/common-patterns/workflow-composition.mdx +27 -17
  166. package/docs/cookbook/index.mdx +22 -22
  167. package/docs/cookbook/integrations/ai-sdk.mdx +63 -48
  168. package/docs/cookbook/integrations/chat-sdk.mdx +46 -33
  169. package/docs/cookbook/integrations/sandbox.mdx +58 -45
  170. package/docs/deploying.mdx +106 -0
  171. package/docs/errors/abort-signal-timeout-in-workflow.mdx +16 -12
  172. package/docs/errors/corrupted-event-log.mdx +39 -18
  173. package/docs/errors/deployment-mismatch.mdx +71 -0
  174. package/docs/errors/fetch-in-workflow.mdx +15 -14
  175. package/docs/errors/hook-conflict.mdx +38 -11
  176. package/docs/errors/hook-force-claimed.mdx +96 -0
  177. package/docs/errors/index.mdx +24 -37
  178. package/docs/errors/node-js-module-in-workflow.mdx +9 -5
  179. package/docs/errors/replay-divergence.mdx +27 -0
  180. package/docs/errors/run-expired.mdx +85 -0
  181. package/docs/errors/runtime-decryption-failed.mdx +77 -0
  182. package/docs/errors/serialization-failed.mdx +44 -12
  183. package/docs/errors/start-invalid-workflow-function.mdx +9 -5
  184. package/docs/errors/step-executed-multiple-times.mdx +23 -0
  185. package/docs/errors/step-not-registered.mdx +6 -6
  186. package/docs/errors/timeout-in-workflow.mdx +12 -8
  187. package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
  188. package/docs/errors/webhook-response-not-sent.mdx +20 -16
  189. package/docs/errors/workflow-not-registered.mdx +5 -5
  190. package/docs/foundations/cancellation.mdx +31 -32
  191. package/docs/foundations/errors-and-retries.mdx +54 -11
  192. package/docs/foundations/hooks.mdx +98 -35
  193. package/docs/foundations/idempotency.mdx +267 -12
  194. package/docs/foundations/index.mdx +1 -26
  195. package/docs/foundations/serialization.mdx +22 -22
  196. package/docs/foundations/starting-workflows.mdx +104 -30
  197. package/docs/foundations/streaming.mdx +108 -60
  198. package/docs/foundations/versioning.mdx +4 -4
  199. package/docs/foundations/workflows-and-steps.mdx +9 -9
  200. package/docs/getting-started/astro.mdx +22 -18
  201. package/docs/getting-started/express.mdx +15 -11
  202. package/docs/getting-started/fastify.mdx +15 -11
  203. package/docs/getting-started/hono.mdx +15 -11
  204. package/docs/getting-started/index.mdx +10 -3
  205. package/docs/getting-started/meta.json +3 -1
  206. package/docs/getting-started/nestjs.mdx +264 -21
  207. package/docs/getting-started/next.mdx +18 -14
  208. package/docs/getting-started/nitro.mdx +22 -18
  209. package/docs/getting-started/nuxt.mdx +15 -11
  210. package/docs/getting-started/python.mdx +190 -41
  211. package/docs/getting-started/react-router/index.mdx +33 -0
  212. package/docs/getting-started/react-router/meta.json +5 -0
  213. package/docs/getting-started/react-router/v7.mdx +237 -0
  214. package/docs/getting-started/react-router/v8.mdx +232 -0
  215. package/docs/getting-started/sveltekit.mdx +20 -16
  216. package/docs/getting-started/tanstack-start.mdx +17 -13
  217. package/docs/getting-started/vite.mdx +15 -11
  218. package/docs/how-it-works/cancellation.mdx +63 -63
  219. package/docs/how-it-works/code-transform.mdx +82 -66
  220. package/docs/how-it-works/encryption.mdx +30 -26
  221. package/docs/how-it-works/event-sourcing.mdx +132 -35
  222. package/docs/how-it-works/framework-integrations.mdx +96 -337
  223. package/docs/how-it-works/understanding-directives.mdx +22 -22
  224. package/docs/internal/index.mdx +6 -4
  225. package/docs/internal/meta.json +6 -1
  226. package/docs/internal/nitro-native-build.mdx +38 -0
  227. package/docs/internal/nitro-web-ui.mdx +24 -0
  228. package/docs/internal/serializable-abort-controller.mdx +7 -7
  229. package/docs/meta.json +4 -2
  230. package/docs/observability/attributes.mdx +91 -21
  231. package/docs/observability/index.mdx +29 -15
  232. package/docs/observability/lifecycle-hooks.mdx +95 -0
  233. package/docs/observability/meta.json +1 -1
  234. package/docs/observability/retention.mdx +95 -0
  235. package/docs/observability/tracing.mdx +124 -0
  236. package/docs/testing/index.mdx +120 -38
  237. package/docs/testing/server-based.mdx +10 -10
  238. package/docs/whats-new.mdx +190 -0
  239. package/docs/worlds/building-a-world.mdx +538 -0
  240. package/docs/worlds/local.mdx +129 -0
  241. package/docs/worlds/meta.json +10 -0
  242. package/docs/worlds/postgres.mdx +424 -0
  243. package/docs/worlds/upgrading-to-v5.mdx +162 -0
  244. package/docs/worlds/vercel.mdx +345 -0
  245. package/package.json +17 -14
  246. package/docs/api-reference/workflow/experimental-set-attributes.mdx +0 -63
  247. package/docs/api-reference/workflow-api/world/index.mdx +0 -58
  248. package/docs/api-reference/workflow-api/world/meta.json +0 -4
  249. package/docs/api-reference/workflow-api/world/observability.mdx +0 -164
  250. package/docs/api-reference/workflow-api/world/queue.mdx +0 -86
  251. package/docs/deploying/building-a-world.mdx +0 -251
  252. package/docs/deploying/index.mdx +0 -95
  253. package/docs/deploying/meta.json +0 -4
  254. package/docs/deploying/world/local-world.mdx +0 -84
  255. package/docs/deploying/world/meta.json +0 -4
  256. package/docs/deploying/world/postgres-world.mdx +0 -224
  257. package/docs/deploying/world/vercel-world.mdx +0 -181
  258. package/docs/migration-guides/index.mdx +0 -34
  259. package/docs/migration-guides/meta.json +0 -9
  260. package/docs/migration-guides/migrating-from-aws-step-functions.mdx +0 -358
  261. package/docs/migration-guides/migrating-from-inngest.mdx +0 -304
  262. package/docs/migration-guides/migrating-from-temporal.mdx +0 -313
  263. package/docs/migration-guides/migrating-from-trigger-dev.mdx +0 -328
@@ -9,10 +9,15 @@ related:
9
9
  - /docs/foundations/workflows-and-steps
10
10
  ---
11
11
 
12
- This guide will walk through setting up your first workflow in a NestJS app. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
12
+ <CopyPrompt
13
+ text="In this NestJS app, run `npm i workflow @workflow/nest` and `npm i -D @swc/cli @swc/core`. Configure `nest-cli.json` with `compilerOptions.builder: &quot;swc&quot;` and `deleteOutDir: true`. Run `npx @workflow/nest init`, add `.swcrc` to `.gitignore`, and set package scripts `prebuild: &quot;npx @workflow/nest init --force&quot;` and `start:dev: &quot;npx @workflow/nest init --force && nest start --watch&quot;`. Import `WorkflowModule.forRoot()` from `@workflow/nest` in `src/app.module.ts` (use `{ moduleType: &quot;commonjs&quot;, distDir: &quot;dist&quot; }` if compiling CommonJS). Create `src/workflows/user-signup.ts` with `&quot;use workflow&quot;`, `sleep`, and `&quot;use step&quot;` helpers. Add a `POST /signup` controller method that reads `email`, calls `start(handleUserSignup, [email])` from `workflow/api`, and returns JSON. Run `npm run start:dev`, call `curl -X POST --json '{&quot;email&quot;:&quot;hello@example.com&quot;}' http://localhost:3000/signup`, and inspect with `npx workflow web` or `npx workflow inspect runs`."
14
+ />
15
+
16
+ Set up your first durable workflow in a NestJS app and learn the core Workflow SDK concepts.
13
17
 
14
18
  <Callout>
15
- NestJS integration is experimental and not yet supported for deployment to Vercel.
19
+ NestJS integration is experimental. Deployment to Vercel is supported via the
20
+ `workflow-nest build --vercel` command. See [Deploy to Vercel](#deploy-to-vercel) below.
16
21
  </Callout>
17
22
 
18
23
  ---
@@ -20,7 +25,7 @@ NestJS integration is experimental and not yet supported for deployment to Verce
20
25
  <Steps>
21
26
 
22
27
  <Step>
23
- ## Create Your NestJS Project
28
+ ## Create your NestJS project
24
29
 
25
30
  Start by creating a new NestJS project using the NestJS CLI.
26
31
 
@@ -41,7 +46,7 @@ cd my-workflow-app
41
46
  npm i workflow @workflow/nest
42
47
  ```
43
48
 
44
- ### Choose Your Module Format
49
+ ### Choose your module format
45
50
 
46
51
  NestJS projects using `@workflow/nest` can compile as either ESM or CommonJS. Choose the setup that matches your SWC output instead of assuming ESM is required.
47
52
 
@@ -107,7 +112,7 @@ Ensure your `nest-cli.json` has SWC as the builder:
107
112
  }
108
113
  ```
109
114
 
110
- ### Initialize SWC Configuration
115
+ ### Initialize SWC configuration
111
116
 
112
117
  Run the init command to generate the SWC configuration:
113
118
 
@@ -115,7 +120,7 @@ Run the init command to generate the SWC configuration:
115
120
  npx @workflow/nest init
116
121
  ```
117
122
 
118
- This creates a `.swcrc` file configured with the Workflow SWC plugin for client-mode transformations.
123
+ This creates a `.swcrc` file configured with the Workflow SWC plugin for step-mode transformations.
119
124
 
120
125
  <Callout>
121
126
  Add `.swcrc` to your `.gitignore` as it contains machine-specific absolute paths that shouldn't be committed.
@@ -138,10 +143,10 @@ Add scripts to regenerate the SWC configuration before builds:
138
143
  <Accordion type="single" collapsible>
139
144
  <AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
140
145
  <AccordionTrigger className="[&_p]:my-0 text-lg [&_p]:text-foreground">
141
- Setup IntelliSense for TypeScript (Optional)
146
+ Set up IntelliSense for TypeScript (optional)
142
147
  </AccordionTrigger>
143
148
  <AccordionContent className="[&_p]:my-2">
144
- To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json`:
149
+ To enable helpful hints in your IDE, set up the workflow plugin in `tsconfig.json`:
145
150
 
146
151
  ```json title="tsconfig.json" lineNumbers
147
152
  {
@@ -203,7 +208,7 @@ The `WorkflowModule` handles workflow bundle building and provides HTTP routing
203
208
 
204
209
  <Step>
205
210
 
206
- ## Create Your First Workflow
211
+ ## Create your first workflow
207
212
 
208
213
  Create a new file for our first workflow in the `src/workflows` directory:
209
214
 
@@ -236,14 +241,14 @@ export async function handleUserSignup(email: string) {
236
241
  }
237
242
  ```
238
243
 
239
- We'll fill in those functions next, but let's take a look at this code:
244
+ We'll fill in those functions next, but first review this code:
240
245
 
241
246
  - We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
242
247
  - The Workflow SDK's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.
243
248
 
244
- ## Create Your Workflow Steps
249
+ ## Create your workflow steps
245
250
 
246
- Let's now define those missing functions.
251
+ Define the missing functions.
247
252
 
248
253
  ```typescript title="src/workflows/user-signup.ts" lineNumbers
249
254
  import { FatalError } from "workflow";
@@ -284,7 +289,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
284
289
 
285
290
  Taking a look at this code:
286
291
 
287
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
292
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
288
293
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
289
294
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
290
295
 
@@ -297,7 +302,7 @@ Taking a look at this code:
297
302
 
298
303
  <Step>
299
304
 
300
- ## Create Your Controller
305
+ ## Create your controller
301
306
 
302
307
  To invoke your new workflow, update your controller with a new endpoint:
303
308
 
@@ -357,11 +362,67 @@ npx workflow inspect runs
357
362
 
358
363
  </Step>
359
364
 
365
+ <Step>
366
+
367
+ ## Deploy to Vercel
368
+
369
+ Because NestJS is not a Vercel-native framework, the Workflow SDK produces a
370
+ [Build Output API](https://vercel.com/docs/build-output-api) directory for you. This emits the
371
+ workflow queue-consumer function (registered with `experimentalTriggers` so Vercel's queue can
372
+ discover it) alongside your NestJS app as a catch-all function. Without it, workflow runs stay
373
+ `pending` because nothing consumes the queue.
374
+
375
+ Add a Vercel-specific entry module that default-exports your Nest app's underlying Node handler:
376
+
377
+ ```typescript title="_vercel/entry.ts" lineNumbers
378
+ import 'reflect-metadata';
379
+ import { NestFactory } from '@nestjs/core';
380
+ import type { NestExpressApplication } from '@nestjs/platform-express';
381
+ import express from 'express';
382
+ import { AppModule } from '../dist/app.module.js';
383
+
384
+ let ready: Promise<express.Express> | undefined;
385
+
386
+ async function createHandler() {
387
+ const app = await NestFactory.create<NestExpressApplication>(AppModule, {
388
+ bodyParser: false,
389
+ });
390
+ app.use(express.json());
391
+ await app.init();
392
+ return app.getHttpAdapter().getInstance();
393
+ }
394
+
395
+ export default async function handler(req: express.Request, res: express.Response) {
396
+ ready ??= createHandler();
397
+ return (await ready)(req, res);
398
+ }
399
+ ```
400
+
401
+ No module change is needed for the in-process build: `skipBuild` defaults to `true` when the
402
+ `VERCEL` environment variable is set, because the Build Output already contains the bundles and
403
+ the deployed filesystem is read-only.
404
+
405
+ Set your build command so the Build Output is produced after `nest build`:
406
+
407
+ ```json title="package.json" lineNumbers
408
+ {
409
+ "scripts": {
410
+ "vercel-build": "workflow-nest init --force && nest build && workflow-nest build --vercel --dirs src/workflows --entry _vercel/entry.ts"
411
+ }
412
+ }
413
+ ```
414
+
415
+ Deploy as usual. `workflow-nest build --vercel` runs automatically on Vercel (it also detects the
416
+ `VERCEL` environment variable), writing `.vercel/output` with the consumer function so your runs
417
+ execute instead of staying `pending`.
418
+
419
+ </Step>
420
+
360
421
  </Steps>
361
422
 
362
423
  ---
363
424
 
364
- ## Configuration Options
425
+ ## Configuration options
365
426
 
366
427
  The `WorkflowModule.forRoot()` method accepts optional configuration:
367
428
 
@@ -375,7 +436,9 @@ WorkflowModule.forRoot({
375
436
  // Output directory for generated bundles (default: '.nestjs/workflow')
376
437
  outDir: '.nestjs/workflow',
377
438
 
378
- // Skip building in production when bundles are pre-built
439
+ // Skip building when bundles are pre-built with `workflow-nest build`
440
+ // (default: true when VERCEL is set, false otherwise). Startup fails if the
441
+ // bundles are missing.
379
442
  skipBuild: false,
380
443
 
381
444
  // SWC module type: 'es6' (default) or 'commonjs'
@@ -387,24 +450,203 @@ WorkflowModule.forRoot({
387
450
  // Should match the outDir in your tsconfig.json
388
451
  distDir: 'dist',
389
452
 
390
- // Source maps on generated workflow bundles (default: 'inline').
453
+ // Source maps on generated workflow bundles (default: 'inline' in
454
+ // development, false in production).
391
455
  // Accepts the same values as esbuild's sourcemap option: true, false,
392
456
  // 'inline', 'linked', 'external', 'both'. Set to false for smaller
393
- // function bundles (useful for staying under the Vercel 250MB function
457
+ // function bundles (useful for staying under the Vercel 250 MB function
394
458
  // size limit) at the cost of stack traces pointing at generated code.
395
459
  // Can also be set via the WORKFLOW_SOURCEMAP environment variable.
396
460
  sourcemap: 'inline',
461
+
462
+ // Route prefix the workflow endpoints are served under. Leave unset to adopt
463
+ // app.setGlobalPrefix() automatically; set it when a reverse proxy mounts the
464
+ // app on a sub-path NestJS does not know about. See "Global prefixes" below.
465
+ basePath: '/api',
466
+
467
+ // Start the target World's background workers with the app and close them on
468
+ // shutdown. Self-hosted Worlds (for example @workflow/world-postgres) need
469
+ // this or runs are created and never picked up. Leave off on Vercel.
470
+ manageWorldLifecycle: false,
471
+
472
+ // Load the generated bundles during startup instead of on the first request
473
+ // (default: true, or false when VERCEL is set because dedicated functions
474
+ // serve the bundles there).
475
+ preloadBundles: true,
476
+ });
477
+ ```
478
+
479
+ Options can also come from other providers with `forRootAsync`:
480
+
481
+ {/*@skip-typecheck - Configuration snippet, imports shown above*/}
482
+
483
+ ```typescript
484
+ WorkflowModule.forRootAsync({
485
+ imports: [ConfigModule],
486
+ inject: [ConfigService],
487
+ useFactory: (config: ConfigService) => ({
488
+ basePath: config.get('API_PREFIX'),
489
+ }),
397
490
  });
398
491
  ```
399
492
 
493
+ ---
494
+
495
+ ## Global prefixes and sub-paths
496
+
497
+ `app.setGlobalPrefix()` moves the workflow routes. The SDK has to generate its
498
+ queue callback and webhook URLs under the same prefix, or every delivery 404s and
499
+ runs stay `pending`.
500
+
501
+ `WorkflowModule` reads the global prefix during startup and adopts it, so this
502
+ works with no configuration:
503
+
504
+ {/*@skip-typecheck - Bootstrap snippet*/}
505
+
506
+ ```typescript
507
+ const app = await NestFactory.create(AppModule);
508
+ app.setGlobalPrefix('api'); // workflow URLs become /api/.well-known/workflow/v1/...
509
+ await app.listen(3000);
510
+ ```
511
+
512
+ Set `basePath` explicitly when the prefix is applied outside NestJS, for example
513
+ by a reverse proxy that strips it before the request reaches your app. An
514
+ explicit `basePath` wins over the global prefix, and a disagreement between the
515
+ two is logged at startup.
516
+
517
+ For Vercel, pass the same value to the build so the deployed queue-consumer
518
+ function generates matching URLs:
519
+
520
+ ```bash
521
+ workflow-nest build --vercel --base-path /api
522
+ ```
523
+
524
+ <Callout type="warn">
525
+ `app.enableVersioning()` moves the workflow routes the same way, and is not
526
+ handled automatically. Exclude the workflow controller from versioning, or mount
527
+ it where the SDK expects it.
528
+ </Callout>
529
+
530
+ ---
531
+
532
+ ## Raw request bodies
533
+
534
+ The workflow routes are a byte pipe. A webhook that verifies a signature over its
535
+ raw body (Stripe, GitHub, Shopify, Slack) only works if the bytes the sender
536
+ signed reach the workflow unchanged, and a body parser that has already turned
537
+ the request into an object destroys them.
538
+
539
+ Create the app with `rawBody` so the original bytes stay available:
540
+
541
+ {/*@skip-typecheck - Bootstrap snippet*/}
542
+
543
+ ```typescript
544
+ const app = await NestFactory.create(AppModule, { rawBody: true });
545
+ ```
546
+
547
+ Without it, `@workflow/nest` falls back to re-serializing the parsed body with
548
+ `JSON.stringify` and logs a warning once. That changes whitespace and key order,
549
+ so signature verification fails.
550
+
551
+ Content types no body parser claims (XML, `application/x-www-form-urlencoded`
552
+ without the parser registered, custom media types) are read straight from the
553
+ request stream and need no configuration.
554
+
555
+ <Callout type="info">
556
+ On Vercel the webhook route is served by its own function rather than by your
557
+ NestJS app, so this only affects self-hosted deployments.
558
+ </Callout>
559
+
560
+ ---
561
+
562
+ ## NestJS dependency injection is not available in workflows and steps
563
+
564
+ Workflows and steps do not run inside your NestJS application. They are compiled
565
+ into separate bundles, so **the Nest injector, your providers, and anything
566
+ built on the request context are out of reach from `"use workflow"` and
567
+ `"use step"` code.**
568
+
569
+ Concretely, none of these work inside a step:
570
+
571
+ - injecting a provider, or resolving one with `app.get(MyService)`
572
+ - `@Injectable()` classes reached through a module-level reference to the app
573
+ - request-scoped providers, and `AsyncLocalStorage` context such as `nestjs-cls`
574
+ - guards, interceptors, pipes, and filters
575
+ - the Nest `Logger`
576
+
577
+ Two mechanics cause this, and neither has a workaround:
578
+
579
+ 1. A step's bundle gets **its own copy** of any application file it imports.
580
+ Module-level state is therefore duplicated, and a class imported into a step
581
+ is a different class object from the one your module registered. Nest uses the
582
+ class itself as the injection token, so `app.get(MyService)` from a step
583
+ raises `UnknownElementException` even when it can reach the app.
584
+ 2. On Vercel, workflows and steps run in the queue-consumer function, a separate
585
+ function from the one serving your NestJS app. There is no shared process to
586
+ reach into.
587
+
588
+ Write steps as plain functions over their arguments, and keep the wiring in your
589
+ controllers and providers:
590
+
591
+ {/*@skip-typecheck - Illustrates the pattern, not a complete app*/}
592
+
593
+ ```typescript
594
+ // A step takes what it needs as arguments and builds its own clients.
595
+ async function chargeCustomer(customerId: string, cents: number) {
596
+ 'use step';
597
+ const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!);
598
+ return await stripe.charges.create({ customer: customerId, amount: cents });
599
+ }
600
+
601
+ // The controller stays a normal Nest controller with normal DI.
602
+ @Controller('billing')
603
+ export class BillingController {
604
+ constructor(private readonly customers: CustomerService) {}
605
+
606
+ @Post('charge')
607
+ async charge(@Body() body: { id: string }) {
608
+ const customer = await this.customers.find(body.id);
609
+ // Pass plain, serializable values into the workflow.
610
+ await start(billingWorkflow, [customer.id, customer.planCents]);
611
+ return { started: true };
612
+ }
613
+ }
614
+ ```
615
+
616
+ Configuration a step needs should come from the environment rather than
617
+ `ConfigService`, and shared logic should live in plain modules that a step can
618
+ import without pulling in `@nestjs/common`.
619
+
620
+ <Callout type="info">
621
+ Importing a file that uses `@nestjs/common` into a step is supported and builds
622
+ correctly, it simply gives you a class with no injected dependencies. Prefer
623
+ plain functions so the intent is clear.
624
+ </Callout>
625
+
626
+ ---
627
+
628
+ ## Production checklist
629
+
630
+ - Run `workflow-nest build` in your build step and set `skipBuild: true`, or
631
+ leave `skipBuild` unset so the bundles are built during startup. With
632
+ `skipBuild` set and no bundles present, startup fails with an explicit error
633
+ rather than serving broken workflow routes.
634
+ - Create the app with `{ rawBody: true }` if you receive signed webhooks.
635
+ - Set `basePath` (or rely on the adopted global prefix) so generated URLs match
636
+ the routes NestJS serves.
637
+ - Set `manageWorldLifecycle: true` for a self-hosted World, and call
638
+ `app.enableShutdownHooks()` so the World is closed on a signal.
639
+ - `skipBuild` defaults to `true` when the `VERCEL` environment variable is set,
640
+ so no Vercel-specific branch is needed in your module configuration.
641
+
400
642
  ## Troubleshooting
401
643
 
402
644
  ### `start()` says it received an invalid workflow function
403
645
 
404
646
  If you see this error:
405
647
 
406
- ```
407
- 'start' received an invalid workflow function. Ensure the Workflow Development Kit is configured correctly and the function includes a 'use workflow' directive.
648
+ ```text
649
+ 'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.
408
650
  ```
409
651
 
410
652
  Check both of these first:
@@ -413,7 +655,8 @@ Check both of these first:
413
655
  2. Your NestJS app imports and registers the `WorkflowModule`.
414
656
 
415
657
  See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function) for full examples and fixes.
416
- ## Next Steps
658
+
659
+ ## Next steps
417
660
 
418
661
  - Learn more about the [Foundations](/docs/foundations).
419
662
  - Check [Errors](/docs/errors) if you encounter issues.
@@ -7,13 +7,17 @@ prerequisites:
7
7
  - /docs/getting-started
8
8
  related:
9
9
  - /docs/api-reference/workflow-next
10
- - /docs/deploying/world/vercel-world
10
+ - /worlds/vercel
11
11
  ---
12
12
 
13
+ <CopyPrompt
14
+ text="In this Next.js app, run `npm i workflow`. Wrap `next.config.ts` with `withWorkflow` from `workflow/next`. If the app has `proxy.ts` or middleware, exclude `.well-known/workflow/` from its matcher. Add `workflows/user-signup.ts` exporting `handleUserSignup(email)` with `&quot;use workflow&quot;`, `sleep` from `workflow`, and `&quot;use step&quot;` helper functions that create a user, send a welcome email, and send an onboarding email. Add `app/api/signup/route.ts` with a POST handler that reads `{ email }`, calls `start(handleUserSignup, [email])` from `workflow/api`, and returns JSON. Run `npm run dev`, trigger `curl -X POST --json '{&quot;email&quot;:&quot;hello@example.com&quot;}' http://localhost:3000/api/signup`, and inspect with `npx workflow web` or `npx workflow inspect runs`."
15
+ />
16
+
13
17
  <Steps>
14
18
 
15
19
  <Step>
16
- ## Create Your Next.js Project
20
+ ## Create your Next.js project
17
21
 
18
22
  Start by creating a new Next.js project. This command will create a new directory named `my-workflow-app` and set up a Next.js project inside it.
19
23
 
@@ -85,7 +89,7 @@ If your Next.js app has a [proxy handler](https://nextjs.org/docs/app/api-refere
85
89
  (formerly known as "middleware"), you'll need to update the matcher pattern to exclude Workflow's
86
90
  internal paths to prevent the proxy handler from running on them.
87
91
 
88
- If you see `[local world] Queue operation failed` with `Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer`, your proxy matcher is still intercepting Workflow's internal `POST /.well-known/workflow/v1/flow` request. This is especially easy to miss in Next.js 16, where `proxy.ts` replaced `middleware.ts`.
92
+ If you see `[local world] Queue operation failed` with `Cannot perform ArrayBuffer.prototype.slice on a detached ArrayBuffer`, your proxy matcher is still intercepting Workflow's internal `POST /.well-known/workflow/v1/flow` request. This issue can be hard to spot in Next.js 16, where `proxy.ts` replaced `middleware.ts`.
89
93
 
90
94
  Add `.well-known/workflow/*` to your matcher exclusion list:
91
95
 
@@ -117,7 +121,7 @@ This ensures that internal Workflow paths are not intercepted by your middleware
117
121
 
118
122
  <Step>
119
123
 
120
- ## Create Your First Workflow
124
+ ## Create your first workflow
121
125
 
122
126
  Create a new file for our first workflow:
123
127
 
@@ -140,14 +144,14 @@ export async function handleUserSignup(email: string) {
140
144
 
141
145
  ```
142
146
 
143
- We'll fill in those functions next, but let's take a look at this code:
147
+ We'll fill in those functions next. The current code does the following:
144
148
 
145
149
  * We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
146
150
  * The Workflow SDK's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.
147
151
 
148
- ## Create Your Workflow Steps
152
+ ## Create your workflow steps
149
153
 
150
- Let's now define those missing functions.
154
+ Define the missing functions.
151
155
 
152
156
  ```typescript title="workflows/user-signup.ts" lineNumbers
153
157
  import { FatalError } from "workflow"
@@ -188,7 +192,7 @@ async function sendOnboardingEmail(user: { id: string; email: string}) {
188
192
 
189
193
  Taking a look at this code:
190
194
 
191
- * Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
195
+ * Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
192
196
  * If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
193
197
  * Steps can throw a `FatalError` if an error is intentional and should not be retried.
194
198
 
@@ -200,7 +204,7 @@ We'll dive deeper into workflows, steps, and other ways to suspend or handle eve
200
204
 
201
205
  <Step>
202
206
 
203
- ## Create Your Route Handler
207
+ ## Create your route handler
204
208
 
205
209
  To invoke your new workflow, we'll need to add your workflow to a `POST` API Route Handler, `app/api/signup/route.ts`, with the following code:
206
210
 
@@ -272,12 +276,12 @@ Check the [Deploying](/docs/deploying) section to learn how your workflows can b
272
276
 
273
277
  If you see this error when upgrading to Next.js 16.1 or later:
274
278
 
275
- ```
279
+ ```text
276
280
  Build error occurred
277
281
  Error: Cannot find module 'next/dist/lib/server-external-packages.json'
278
282
  ```
279
283
 
280
- Upgrade to `workflow@4.0.1-beta.26` or later:
284
+ Upgrade `workflow` to the latest release:
281
285
 
282
286
  ```package-install
283
287
  workflow@latest
@@ -311,8 +315,8 @@ Without this configuration, you may experience intermittent issues where workflo
311
315
 
312
316
  If you see this error:
313
317
 
314
- ```
315
- 'start' received an invalid workflow function. Ensure the Workflow Development Kit is configured correctly and the function includes a 'use workflow' directive.
318
+ ```text
319
+ 'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.
316
320
  ```
317
321
 
318
322
  Check both of these first:
@@ -322,7 +326,7 @@ Check both of these first:
322
326
 
323
327
  See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function) for full examples and fixes.
324
328
 
325
- ## Next Steps
329
+ ## Next steps
326
330
 
327
331
  * Learn more about the [Foundations](/docs/foundations).
328
332
  * Check [Errors](/docs/errors) if you encounter issues.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: Nitro
3
- description: This guide will walk through setting up your first workflow in a Nitro v3 project. Along the way, you'll learn more about the concepts that are fundamental to using the Workflow SDK in your own projects.
3
+ description: Set up your first durable workflow in a Nitro v3 project.
4
4
  type: guide
5
5
  summary: Set up Workflow SDK in a Nitro app.
6
6
  prerequisites:
@@ -9,12 +9,16 @@ related:
9
9
  - /docs/foundations/workflows-and-steps
10
10
  ---
11
11
 
12
+ <CopyPrompt
13
+ text="In this Nitro app, run `npm i workflow`. In `nitro.config.ts`, use `defineConfig` from `nitro`, set `serverDir: &quot;./server&quot;`, and add `modules: [&quot;workflow/nitro&quot;]`. Add the TypeScript plugin `{ &quot;name&quot;: &quot;workflow&quot; }` to `tsconfig.json` if TypeScript is used. Create `workflows/user-signup.ts` with `handleUserSignup(email)`, `&quot;use workflow&quot;`, `sleep` from `workflow`, and `&quot;use step&quot;` helpers. Add `server/api/signup.post.ts` using `defineEventHandler` from `nitro/h3` and `start` from `workflow/api` to start the workflow from `{ email }`. Run `npm run dev`, call `curl -X POST --json '{&quot;email&quot;:&quot;hello@example.com&quot;}' http://localhost:3000/api/signup`, then inspect with `npx workflow web` or `npx workflow inspect runs`."
14
+ />
15
+
12
16
  <Steps>
13
17
 
14
18
  <Step>
15
- ## Create Your Nitro Project
19
+ ## Create your Nitro project
16
20
 
17
- Start by creating a new [Nitro v3](https://v3.nitro.build/) project. This command will create a new directory named `nitro-app` and setup a Nitro project inside it.
21
+ Create a [Nitro v3](https://v3.nitro.build/) project in a new directory named `nitro-app`:
18
22
 
19
23
  ```bash
20
24
  npx create-nitro-app
@@ -34,7 +38,7 @@ npm i workflow
34
38
 
35
39
  ### Configure Nitro
36
40
 
37
- Add `workflow/nitro` module to your `nitro.config.ts` This enables usage of the `"use workflow"` and `"use step"` directives.
41
+ Add the `workflow/nitro` module to your `nitro.config.ts`. This enables the `"use workflow"` and `"use step"` directives.
38
42
 
39
43
  ```typescript title="nitro.config.ts" lineNumbers
40
44
  import { defineConfig } from "nitro";
@@ -66,15 +70,15 @@ export default defineConfig({
66
70
  | --- | --- | --- | --- |
67
71
  | `dirs` | `string[]` | — | Directories to scan for workflows and steps. By default, `workflows/` is scanned from the project root and all layer source directories. |
68
72
  | `runtime` | `string` | `'nodejs22.x'` | Node.js runtime version for Vercel Functions (e.g. `'nodejs22.x'`, `'nodejs24.x'`). |
69
- | `sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` | Controls source maps on generated workflow bundles. Accepts the same values as esbuild's `sourcemap` option. Set to `false` for smaller function bundles (useful for staying under the Vercel 250MB function size limit) at the cost of stack traces pointing at generated code. Can also be set via the `WORKFLOW_SOURCEMAP` environment variable. |
73
+ | `sourcemap` | `boolean \| 'inline' \| 'linked' \| 'external' \| 'both'` | `'inline'` (dev) / `false` (prod) | Controls source maps on generated workflow bundles. Accepts the same values as esbuild's `sourcemap` option. Defaults to `'inline'` in development and `false` in production (smaller function bundles, which helps stay under the Vercel 250 MB function size limit). Set it explicitly, or use the `WORKFLOW_SOURCEMAP` environment variable, to override in either environment. |
70
74
 
71
75
  <Accordion type="single" collapsible>
72
76
  <AccordionItem value="typescript-intellisense" className="[&_h3]:my-0">
73
77
  <AccordionTrigger className="[&_p]:my-0 text-lg [&_p]:text-foreground">
74
- Setup IntelliSense for TypeScript (Optional)
78
+ Set up IntelliSense for TypeScript (optional)
75
79
  </AccordionTrigger>
76
80
  <AccordionContent className="[&_p]:my-2">
77
- To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json`:
81
+ To enable helpful hints in your IDE, set up the workflow plugin in `tsconfig.json`:
78
82
 
79
83
  ```json title="tsconfig.json" lineNumbers
80
84
  {
@@ -98,7 +102,7 @@ To enable helpful hints in your IDE, setup the workflow plugin in `tsconfig.json
98
102
 
99
103
  <Step>
100
104
 
101
- ## Create Your First Workflow
105
+ ## Create your first workflow
102
106
 
103
107
  Create a new file for our first workflow:
104
108
 
@@ -120,14 +124,14 @@ export async function handleUserSignup(email: string) {
120
124
  }
121
125
  ```
122
126
 
123
- We'll fill in those functions next, but let's take a look at this code:
127
+ We'll fill in those functions next, but first review this code:
124
128
 
125
129
  - We define a **workflow** function with the directive `"use workflow"`. Think of the workflow function as the _orchestrator_ of individual **steps**.
126
130
  - The Workflow SDK's `sleep` function allows us to suspend execution of the workflow without using up any resources. A sleep can be a few seconds, hours, days, or even months long.
127
131
 
128
- ## Create Your Workflow Steps
132
+ ## Create your workflow steps
129
133
 
130
- Let's now define those missing functions.
134
+ Define the missing functions.
131
135
 
132
136
  ```typescript title="workflows/user-signup.ts" lineNumbers
133
137
  import { FatalError } from "workflow";
@@ -168,7 +172,7 @@ async function sendOnboardingEmail(user: { id: string; email: string }) {
168
172
 
169
173
  Taking a look at this code:
170
174
 
171
- - Business logic lives inside **steps**. When a step is invoked inside a **workflow**, it gets enqueued to run on a separate request while the workflow is suspended, just like `sleep`.
175
+ - Business logic lives inside **steps**. When a workflow invokes a step, the workflow suspends while the step runs with full Node.js access. The combined handler may execute it inline; queued retries and continuations return through the same flow route.
172
176
  - If a step throws an error, like in `sendWelcomeEmail`, the step will automatically be retried until it succeeds (or hits the step's max retry count).
173
177
  - Steps can throw a `FatalError` if an error is intentional and should not be retried.
174
178
 
@@ -181,7 +185,7 @@ Taking a look at this code:
181
185
 
182
186
  <Step>
183
187
 
184
- ## Create Your Route Handler
188
+ ## Create your route handler
185
189
 
186
190
  To invoke your new workflow, we'll create a new API route handler at `server/api/signup.post.ts` with the following code:
187
191
 
@@ -200,7 +204,7 @@ export default defineEventHandler(async ({ req }) => {
200
204
  });
201
205
  ```
202
206
 
203
- This Route Handler creates a `POST` request endpoint at `/api/signup` that will trigger your workflow.
207
+ This route handler creates a `POST` request endpoint at `/api/signup` that triggers your workflow.
204
208
 
205
209
  <Callout>
206
210
  Workflows can be triggered from API routes or any server-side
@@ -244,7 +248,7 @@ npx workflow inspect runs
244
248
 
245
249
  ## Deploying to production
246
250
 
247
- Workflow SDK apps currently work best when deployed to [Vercel](https://vercel.com/home) and needs no special configuration.
251
+ Workflow SDK apps currently work best when deployed to [Vercel](https://vercel.com/home) and need no special configuration.
248
252
 
249
253
  <FluidComputeCallout />
250
254
 
@@ -256,8 +260,8 @@ Check the [Deploying](/docs/deploying) section to learn how your workflows can b
256
260
 
257
261
  If you see this error:
258
262
 
259
- ```
260
- 'start' received an invalid workflow function. Ensure the Workflow Development Kit is configured correctly and the function includes a 'use workflow' directive.
263
+ ```text
264
+ 'start' received an invalid workflow function. Ensure the Workflow SDK is configured correctly and the function includes a 'use workflow' directive.
261
265
  ```
262
266
 
263
267
  Check both of these first:
@@ -267,7 +271,7 @@ Check both of these first:
267
271
 
268
272
  See [start-invalid-workflow-function](/docs/errors/start-invalid-workflow-function) for full examples and fixes.
269
273
 
270
- ## Next Steps
274
+ ## Next steps
271
275
 
272
276
  - Learn more about the [Foundations](/docs/foundations).
273
277
  - Check [Errors](/docs/errors) if you encounter issues.