workflow 5.0.0-beta.43 → 5.0.0-beta.44

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 (182) hide show
  1. package/README.md +6 -4
  2. package/dist/internal/builtins.d.ts +4 -4
  3. package/dist/internal/builtins.js +6 -6
  4. package/docs/ai/chat-session-modeling.mdx +23 -24
  5. package/docs/ai/defining-tools.mdx +5 -6
  6. package/docs/ai/human-in-the-loop.mdx +11 -11
  7. package/docs/ai/index.mdx +20 -20
  8. package/docs/ai/message-queueing.mdx +6 -6
  9. package/docs/ai/meta.json +1 -0
  10. package/docs/ai/resumable-streams.mdx +28 -28
  11. package/docs/ai/sleep-and-delays.mdx +9 -9
  12. package/docs/ai/streaming-updates-from-tools.mdx +4 -4
  13. package/docs/api-reference/vitest/index.mdx +8 -8
  14. package/docs/api-reference/workflow/create-hook.mdx +15 -15
  15. package/docs/api-reference/workflow/create-webhook.mdx +15 -15
  16. package/docs/api-reference/workflow/define-hook.mdx +10 -10
  17. package/docs/api-reference/workflow/fatal-error.mdx +2 -2
  18. package/docs/api-reference/workflow/fetch.mdx +7 -7
  19. package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
  20. package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
  21. package/docs/api-reference/workflow/get-writable.mdx +7 -7
  22. package/docs/api-reference/workflow/index.mdx +1 -1
  23. package/docs/api-reference/workflow/retryable-error.mdx +1 -1
  24. package/docs/api-reference/workflow/set-attributes.mdx +2 -2
  25. package/docs/api-reference/workflow/sleep.mdx +3 -3
  26. package/docs/api-reference/workflow-ai/durable-agent.mdx +42 -42
  27. package/docs/api-reference/workflow-ai/index.mdx +3 -3
  28. package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +28 -28
  29. package/docs/api-reference/workflow-api/get-hook-by-token.mdx +11 -11
  30. package/docs/api-reference/workflow-api/get-run.mdx +10 -10
  31. package/docs/api-reference/workflow-api/index.mdx +2 -4
  32. package/docs/api-reference/workflow-api/resume-hook.mdx +14 -14
  33. package/docs/api-reference/workflow-api/resume-webhook.mdx +3 -3
  34. package/docs/api-reference/workflow-api/start.mdx +16 -15
  35. package/docs/api-reference/workflow-astro/workflow.mdx +3 -3
  36. package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
  37. package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +4 -4
  38. package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
  39. package/docs/api-reference/workflow-errors/index.mdx +6 -6
  40. package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +9 -9
  41. package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
  42. package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +4 -4
  43. package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
  44. package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
  45. package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
  46. package/docs/api-reference/workflow-errors/workflow-error.mdx +4 -4
  47. package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
  48. package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +6 -6
  49. package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +5 -5
  50. package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +4 -4
  51. package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
  52. package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +2 -2
  53. package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
  54. package/docs/api-reference/workflow-globals.mdx +12 -11
  55. package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +2 -2
  56. package/docs/api-reference/workflow-nest/nest-local-builder.mdx +4 -4
  57. package/docs/api-reference/workflow-nest/workflow-controller.mdx +1 -1
  58. package/docs/api-reference/workflow-nest/workflow-module.mdx +4 -4
  59. package/docs/api-reference/workflow-next/with-workflow.mdx +16 -16
  60. package/docs/api-reference/workflow-nitro/index.mdx +6 -6
  61. package/docs/api-reference/workflow-nuxt/index.mdx +4 -4
  62. package/docs/api-reference/workflow-observability/hydrate-data.mdx +5 -5
  63. package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +4 -4
  64. package/docs/api-reference/workflow-observability/index.mdx +6 -8
  65. package/docs/api-reference/workflow-observability/observability-revivers.mdx +2 -2
  66. package/docs/api-reference/workflow-observability/parse-class-name.mdx +3 -3
  67. package/docs/api-reference/workflow-observability/parse-step-name.mdx +4 -4
  68. package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +4 -4
  69. package/docs/api-reference/workflow-runtime/create-world.mdx +8 -8
  70. package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +6 -6
  71. package/docs/api-reference/workflow-runtime/get-world.mdx +4 -4
  72. package/docs/api-reference/workflow-runtime/health-check.mdx +1 -1
  73. package/docs/api-reference/workflow-runtime/index.mdx +2 -4
  74. package/docs/api-reference/workflow-runtime/set-world.mdx +15 -13
  75. package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +6 -5
  76. package/docs/api-reference/workflow-runtime/world/analytics.mdx +9 -9
  77. package/docs/api-reference/workflow-runtime/world/index.mdx +5 -3
  78. package/docs/api-reference/workflow-runtime/world/queue.mdx +11 -11
  79. package/docs/api-reference/workflow-runtime/world/storage.mdx +62 -28
  80. package/docs/api-reference/workflow-runtime/world/streams.mdx +7 -7
  81. package/docs/api-reference/workflow-serde/index.mdx +1 -1
  82. package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +2 -2
  83. package/docs/api-reference/workflow-serde/workflow-serialize.mdx +7 -7
  84. package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +3 -3
  85. package/docs/api-reference/workflow-vite/workflow.mdx +5 -5
  86. package/docs/changelog/attributes-mvp.mdx +39 -39
  87. package/docs/changelog/batched-event-writes.mdx +12 -12
  88. package/docs/changelog/eager-processing.mdx +63 -63
  89. package/docs/changelog/index.mdx +3 -3
  90. package/docs/changelog/lazy-event-creation.md +27 -27
  91. package/docs/changelog/resilient-resume.mdx +5 -5
  92. package/docs/changelog/resilient-start.mdx +14 -14
  93. package/docs/changelog/step-message-ownership.mdx +47 -47
  94. package/docs/changelog/turbo-mode.md +20 -20
  95. package/docs/comparisons/index.mdx +13 -13
  96. package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +15 -15
  97. package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +12 -12
  98. package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +11 -11
  99. package/docs/comparisons/workflow-sdk-vs-inngest.mdx +19 -19
  100. package/docs/comparisons/workflow-sdk-vs-temporal.mdx +23 -23
  101. package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +18 -17
  102. package/docs/configuration/build-and-diagnostics.mdx +5 -5
  103. package/docs/configuration/cli-and-web-ui.mdx +4 -4
  104. package/docs/configuration/runtime-tuning.mdx +86 -23
  105. package/docs/configuration/worlds.mdx +28 -14
  106. package/docs/cookbook/advanced/child-workflows.mdx +25 -25
  107. package/docs/cookbook/advanced/publishing-libraries.mdx +40 -40
  108. package/docs/cookbook/advanced/serializable-steps.mdx +21 -21
  109. package/docs/cookbook/advanced/upgrading-workflows.mdx +31 -31
  110. package/docs/cookbook/agent-patterns/agent-cancellation.mdx +20 -20
  111. package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +22 -22
  112. package/docs/cookbook/common-patterns/batching.mdx +14 -14
  113. package/docs/cookbook/common-patterns/idempotency.mdx +9 -9
  114. package/docs/cookbook/common-patterns/rate-limiting.mdx +3 -3
  115. package/docs/cookbook/common-patterns/saga.mdx +19 -19
  116. package/docs/cookbook/common-patterns/scheduling.mdx +23 -23
  117. package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +26 -26
  118. package/docs/cookbook/common-patterns/timeouts.mdx +23 -23
  119. package/docs/cookbook/common-patterns/webhooks.mdx +6 -6
  120. package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -19
  121. package/docs/cookbook/index.mdx +22 -22
  122. package/docs/cookbook/integrations/ai-sdk.mdx +43 -41
  123. package/docs/cookbook/integrations/chat-sdk.mdx +34 -34
  124. package/docs/cookbook/integrations/sandbox.mdx +46 -46
  125. package/docs/deploying.mdx +15 -15
  126. package/docs/errors/abort-signal-timeout-in-workflow.mdx +12 -12
  127. package/docs/errors/corrupted-event-log.mdx +11 -11
  128. package/docs/errors/deployment-mismatch.mdx +14 -14
  129. package/docs/errors/fetch-in-workflow.mdx +8 -8
  130. package/docs/errors/hook-conflict.mdx +11 -11
  131. package/docs/errors/index.mdx +1 -1
  132. package/docs/errors/node-js-module-in-workflow.mdx +5 -5
  133. package/docs/errors/replay-divergence.mdx +2 -2
  134. package/docs/errors/runtime-decryption-failed.mdx +12 -12
  135. package/docs/errors/serialization-failed.mdx +40 -12
  136. package/docs/errors/start-invalid-workflow-function.mdx +5 -5
  137. package/docs/errors/step-executed-multiple-times.mdx +2 -2
  138. package/docs/errors/step-not-registered.mdx +5 -5
  139. package/docs/errors/timeout-in-workflow.mdx +8 -8
  140. package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
  141. package/docs/errors/webhook-response-not-sent.mdx +16 -16
  142. package/docs/errors/workflow-not-registered.mdx +5 -5
  143. package/docs/foundations/cancellation.mdx +31 -31
  144. package/docs/foundations/errors-and-retries.mdx +42 -11
  145. package/docs/foundations/hooks.mdx +35 -35
  146. package/docs/foundations/idempotency.mdx +9 -9
  147. package/docs/foundations/serialization.mdx +21 -22
  148. package/docs/foundations/starting-workflows.mdx +36 -37
  149. package/docs/foundations/streaming.mdx +46 -41
  150. package/docs/foundations/versioning.mdx +3 -3
  151. package/docs/foundations/workflows-and-steps.mdx +9 -9
  152. package/docs/getting-started/astro.mdx +16 -16
  153. package/docs/getting-started/express.mdx +8 -8
  154. package/docs/getting-started/fastify.mdx +8 -8
  155. package/docs/getting-started/hono.mdx +8 -8
  156. package/docs/getting-started/nestjs.mdx +18 -17
  157. package/docs/getting-started/next.mdx +11 -11
  158. package/docs/getting-started/nitro.mdx +16 -16
  159. package/docs/getting-started/nuxt.mdx +8 -8
  160. package/docs/getting-started/python.mdx +4 -4
  161. package/docs/getting-started/react-router/v7.mdx +1 -1
  162. package/docs/getting-started/react-router/v8.mdx +1 -1
  163. package/docs/getting-started/sveltekit.mdx +14 -14
  164. package/docs/getting-started/tanstack-start.mdx +12 -12
  165. package/docs/getting-started/vite.mdx +8 -8
  166. package/docs/how-it-works/cancellation.mdx +62 -62
  167. package/docs/how-it-works/code-transform.mdx +66 -54
  168. package/docs/how-it-works/encryption.mdx +25 -21
  169. package/docs/how-it-works/event-sourcing.mdx +53 -35
  170. package/docs/how-it-works/framework-integrations.mdx +12 -12
  171. package/docs/how-it-works/understanding-directives.mdx +21 -21
  172. package/docs/internal/index.mdx +6 -6
  173. package/docs/internal/nitro-native-build.mdx +2 -2
  174. package/docs/internal/nitro-web-ui.mdx +4 -4
  175. package/docs/internal/serializable-abort-controller.mdx +7 -7
  176. package/docs/observability/attributes.mdx +3 -3
  177. package/docs/observability/index.mdx +14 -10
  178. package/docs/observability/tracing.mdx +10 -10
  179. package/docs/testing/index.mdx +33 -33
  180. package/docs/testing/server-based.mdx +10 -10
  181. package/docs/whats-new.mdx +185 -0
  182. package/package.json +12 -12
@@ -0,0 +1,185 @@
1
+ ---
2
+ title: What's new in v5?
3
+ description: Workflow SDK 5.0 highlights, breaking changes, and how to upgrade from 4.x.
4
+ type: guide
5
+ summary: See what changed in Workflow SDK 5.0 and how to move an app from 4.x.
6
+ related:
7
+ - /docs/getting-started
8
+ - /docs/configuration
9
+ - /docs/foundations/cancellation
10
+ ---
11
+
12
+ We recommend upgrading to v5 to get all of the performance, cost, and feature improvements listed below. Install the migration skill, then tell your agent to migrate your app from Workflow SDK v4 to v5.
13
+
14
+ ```bash
15
+ npm install workflow@latest
16
+ npx skills add https://github.com/vercel/workflow --skill migrating-workflow-v4-to-v5
17
+ ```
18
+
19
+ <CopyPrompt text="Upgrade this app from Workflow SDK v4 to v5 using the migrating-workflow-v4-to-v5 skill. Bump `workflow` and every `@workflow/*` dependency to ^5.0.0, apply the skill's mechanical rewrites, and report the behavior changes it flags instead of silently changing them. Then verify: reinstall, rebuild, typecheck, run the test suite, and execute one workflow end to end." />
20
+
21
+ <Callout type="info">
22
+ Workflow SDK v4 remains installable as `workflow@4` and receives stability
23
+ fixes. Switch to its documentation with the version picker in the sidebar.
24
+ </Callout>
25
+
26
+ ## Highlights
27
+
28
+ ### Faster and cheaper runs
29
+
30
+ The largest change in v5 has no API surface: the runtime does far less work per unit of progress. The time between calling `start()` and your first step body executing is now less than half of what it was in v4. This is made possible by many smaller optimizations:
31
+
32
+ **A workflow invocation now does as much as it can in a single pass.** In 4.x, progress was largely deferred to the queue: an invocation would execute a step, hand back to the queue, and let a fresh invocation pick up the next one. v5 creates and executes several steps inline per suspension, in parallel, and only uses the queue for a wait, a hook, or when the function approaches its timeout.
33
+
34
+ **The runtime avoids waiting on the persistence layer where it can determine that is safe for your workload.** The runtime skips many API calls when they aren't needed, such as requesting the event log on a run's first invocation. Step creation is folded into step execution rather than being its own round trip. The inline loop consumes the event-log delta from the previous step's write instead of re-listing events. Each optimization is gated on specific runtime conditions and can be turned off individually. See [Runtime tuning](/docs/configuration/runtime-tuning).
35
+
36
+ **The workflow VM is kept alive across inline steps.** Within one invocation, a step-only suspension keeps the live VM and hydrated state, so the next iteration appends only the newly written events instead of rebuilding the sandbox and replaying the whole log. Step inputs made of plain data or standard built-ins keep this fast path; see [`WORKFLOW_RETAINED_VM`](/docs/configuration/runtime-tuning#workflow_retained_vm).
37
+
38
+ **Resuming a hook takes one round trip instead of two.** `resumeHook()` writes the `hook_received` event and dispatches the queue message concurrently, with a `(runId, resumeId)` dedup constraint keeping the two writers converging on exactly one event. See [Resilient hook resumption](/docs/changelog/resilient-resume).
39
+
40
+ **Payloads are compressed** before they are encrypted and sent to the API. Repetitive payloads compress heavily; AI token streams average around 80% smaller. That is less stored data and less to move over the network.
41
+
42
+ On [Vercel Workflows](/worlds/vercel) these benefits compound to reduce compute costs by up to 80% for workflows made of many small steps, and storage cost by up to 70%, depending on the workload. Depending on your setup, you may see similar gains using self-hosted or third-party Worlds.
43
+
44
+ How much work fits in one invocation now scales with the function's own limit: the inline budget is derived from the runtime deadline the World reports, so raising `maxDuration` widens it without configuration. See [`WORKFLOW_V2_TIMEOUT_MS`](/docs/configuration/runtime-tuning#workflow_v2_timeout_ms).
45
+
46
+ ### Multi-region support
47
+
48
+ Workflow run IDs are now tagged with the compute region they were created in, or the region specified when calling `start()`. Worlds can use this to pin execution to that region.
49
+ This is now the default when deploying to Vercel, and run data will automatically be co-located with the compute region that the run was started in.
50
+
51
+ See [Multi-region on the Vercel World](/worlds/vercel#multi-region) for how automatic pinning works and how to [select a region explicitly](/worlds/vercel#explicit-region-selection), and [Building a World](/worlds/building-a-world) for adding regional placement to a custom World.
52
+
53
+ ### Inflight cancellation
54
+
55
+ `AbortController` and `AbortSignal` are now serializable, and signals can be passed into steps, so a workflow can abandon in-flight work without waiting for a step to finish.
56
+
57
+ ```typescript lineNumbers
58
+ import { sleep } from "workflow";
59
+
60
+ export async function raceWithTimeout() {
61
+ "use workflow";
62
+
63
+ const controller = new AbortController(); // [!code highlight]
64
+
65
+ const result = await Promise.race([
66
+ fetchData(controller.signal), // [!code highlight]
67
+ sleep("10s").then(() => null),
68
+ ]);
69
+
70
+ if (result === null) {
71
+ controller.abort(); // [!code highlight]
72
+ }
73
+
74
+ return result;
75
+ }
76
+
77
+ async function fetchData(signal: AbortSignal) {
78
+ "use step";
79
+ const response = await fetch("https://api.example.com/data", { signal });
80
+ return response.json();
81
+ }
82
+ ```
83
+
84
+ The abort reaches a step that is already executing, not just the next one to start, so a `fetch()` in flight when the controller aborts is torn down. Cancellation stays cooperative: a step that ignores its signal still runs to completion.
85
+
86
+ Cancelling from the outside gained detail too: [`run.cancel()`](/docs/api-reference/workflow-api/get-run) accepts a `cancelReason`, recorded on the cancellation event and shown in the run detail view. And cancellation now works in bulk: `workflow cancel` takes `--status pending|running` and `--workflowName` to cancel a batch in one operation, and the runs table in the web UI cancels every selected run in a single request. See [CLI and web UI](/docs/configuration/cli-and-web-ui).
87
+
88
+ See [Cancellation](/docs/foundations/cancellation), [How cancellation works](/docs/how-it-works/cancellation), and the [in-flight cancellation changelog](https://vercel.com/changelog/workflow-sdk-now-supports-inflight-cancellation).
89
+
90
+ ### Run attributes
91
+
92
+ Attach string metadata to a run with [`setAttributes()`](/docs/api-reference/workflow/set-attributes), or seed it at creation with the `attributes` option of [`start()`](/docs/api-reference/workflow-api/start), then search and filter runs by `key=value`. Attributes were available in beta and are generally available in v5 under their final names: the `experimental_setAttributes` alias is gone.
93
+
94
+ Some attributes are set for you: a run started from inside another workflow or step is automatically tagged with the reserved `$parentRunId` and `$rootRunId` attributes, so a whole chain or fan-out of related runs can be found with a single attribute filter.
95
+
96
+ Vercel Observability can search runs by attribute. `workflow inspect` and the local web UI read them from `world.analytics` on any World that implements it.
97
+
98
+ See [Attributes](/docs/observability/attributes).
99
+
100
+ ### Richer serialization
101
+
102
+ Everything that crosses a workflow/step boundary is serialized, and v5 widens what survives the trip with its identity intact. Errors, including your own classes and built-ins like `TypeError`, keep their class and `cause` chain through `WorkflowRunFailedError.cause`:
103
+
104
+ ```typescript lineNumbers
105
+ import { WorkflowRunFailedError } from "workflow/errors";
106
+ import { getRun } from "workflow/api";
107
+ declare class PaymentDeclinedError extends Error {} // @setup
108
+
109
+ try {
110
+ await getRun(runId).returnValue;
111
+ } catch (error) {
112
+ if (
113
+ error instanceof WorkflowRunFailedError &&
114
+ error.cause instanceof PaymentDeclinedError // [!code highlight]
115
+ ) {
116
+ // your class, not a flattened generic Error
117
+ }
118
+ }
119
+ ```
120
+
121
+ Workflow function references and [`Run`](/docs/api-reference/workflow-api/get-run) handles are serializable too, so a step can receive a workflow function to `start()` or a run handle to await. And when a value cannot cross a boundary, the failure is precise instead of generic: dedicated [`SerializationError`](/docs/api-reference/workflow-errors) and structured context-violation errors name the offending value and where it was used.
122
+
123
+ See [Serialization](/docs/foundations/serialization).
124
+
125
+ ### A redesigned trace viewer
126
+
127
+ The trace viewer has been rebuilt with a visible timeline, a minimap, pan, zoom, debug functionality, a new JSON viewer, keyboard navigation, and more.
128
+
129
+ Vercel Observability uses this trace viewer for all runs, v4 included, but with v5, you get the same new design for self-hosted UI and local debugging. See [Observability](/docs/observability).
130
+
131
+ The local tooling around it grew as well: on [Nitro](/docs/getting-started/nitro) the dev server has the web UI built in at `/_workflow`, `workflow inspect runs` accepts `--since`/`--until` listing windows, run lookups by name search past the backend's default 24-hour window, and Worlds can surface their own run fields in `inspect` output. For example, the Vercel World shows each run's region. On any other framework, `createWorkflowWebHandler()` from `@workflow/web/handler` serves the same UI as one `Request` to `Response` handler under a base path of your choosing.
132
+
133
+ Each run also carries more of the infrastructure it ran on. A step attempt records the compute instance that executed it, surfaced as **Compute Instance ID** in the run sidebar and as a `faas.instance` span attribute on flow and step spans, so a run that behaves oddly can be correlated with one warm instance. The sidebar also shows a copyable **Request ID** for looking the invocation up in your platform's logs.
134
+
135
+ ### Custom hook token retention
136
+
137
+ A [Hook](/docs/foundations/hooks) token is normally reserved only while its workflow is running. Pass `experimental_minRetention` to [`createHook()`](/docs/api-reference/workflow/create-hook#keep-a-token-unavailable-after-the-run-ends) to keep the token unavailable for at least a given duration after the Hook is created, so a duplicate request arriving after the original run finished still collides instead of starting fresh work. This allows for durable [run idempotency](/docs/foundations/idempotency#run-idempotency) with custom durations.
138
+
139
+ All three first-party Worlds now implement it: Vercel accepts up to 30 days, and the Local and Postgres Worlds default to the same ceiling (see [`WORKFLOW_LOCAL_HOOK_RETENTION_LIMIT_DAYS`](/docs/configuration/worlds) and its Postgres equivalent). A retained Hook remains readable with [`getHookByToken()`](/docs/api-reference/workflow-api/get-hook-by-token) after its run ends, but cannot be resumed.
140
+
141
+ ### Also new in 5.0
142
+
143
+ - **`start()` from inside a workflow.** Spawn a child run or hand off to a new run directly in a workflow function, without wrapping it in a step. See [Starting workflows](/docs/foundations/starting-workflows).
144
+ - **Stronger hook coordination.** `hook.getConflict()` resolves with the conflicting [`Run`](/docs/api-reference/workflow-api/get-run) rather than a bare `{ runId }`, so a duplicate can `await conflict.status`, `await conflict.returnValue`, or `await conflict.cancel()` directly. See [Run idempotency](/docs/foundations/idempotency#run-idempotency).
145
+ - **Support for more frameworks.** [React Router](/docs/getting-started/react-router) (v7 and v8, via Nitro) and [NestJS](/docs/getting-started/nestjs) are now supported.
146
+ - **A misrouted delivery no longer fails a run.** Runs are pinned to the deployment that created them. A delivery that arrives at a different deployment is now re-routed to the pinned one with backoff instead of failing, and only gives up with the new [`DEPLOYMENT_MISMATCH`](/docs/errors/deployment-mismatch) error once the recovery budget is spent. Nothing executes on the wrong deployment while this happens. In 4.x the same situation surfaced as an unexplained decryption failure.
147
+ - **A run cannot be forked across environments.** `start()` stamps the environment it was called from onto the queue message, and a deployment refuses a delivery whose run was created in a different environment. Previously a preview client and a production deployment could each hold half of one run ID.
148
+ - **An experimental QuickJS VM engine.** Set [`WORKFLOW_VM=quickjs`](/docs/configuration/runtime-tuning#workflow_vm) to run workflow functions in a QuickJS VM compiled to WebAssembly instead of `node:vm`, for platforms that do not provide `node:vm`. Replay semantics are identical, but the available globals are not: check the differences before switching an existing deployment.
149
+ - **An opt-in WebSocket transport for event writes** on the Vercel World, via [`WORKFLOW_EVENTS_TRANSPORT=ws`](/docs/configuration/worlds). HTTP remains the default.
150
+ - **An event arriving mid-replay no longer fails the run.** A hook resume or step completion landing while a replay is in flight used to be able to fail it with [`CORRUPTED_EVENT_LOG`](/docs/errors/corrupted-event-log). Writes now come back with the events the replay had not seen, and the event is held for whichever part of the workflow awaits it. A run only fails when the log is genuinely missing a position.
151
+
152
+ ## Breaking changes
153
+
154
+ ### Application code
155
+
156
+ | Change | What to do |
157
+ | --- | --- |
158
+ | `runStep` removed from `workflow/api` | Call your step function directly; the compiler routes it through the step runtime. |
159
+ | `hook.getConflict()` resolves with a `Run` | Replace `conflict.runId` round trips through `getRun()` inside a step with the accessors on `conflict` directly. `conflict.runId` still works. |
160
+ | `experimental_setAttributes` removed | Import `setAttributes` instead, and `SetAttributesOptions` in place of `ExperimentalSetAttributesOptions`. The deprecated aliases are gone. |
161
+ | [`getWorld()`](/docs/api-reference/workflow-runtime/get-world), [`getWorldHandlers()`](/docs/api-reference/workflow-runtime/get-world-handlers), and [`createWorld()`](/docs/api-reference/workflow-runtime/create-world) are async | They resolve a `Promise` now, so await the call before reaching for anything on it: `const world = await getWorld();` then `await world.start?.();`. This mainly affects the `instrumentation.ts` bootstrap that starts a World with background workers, such as the [Postgres World](/worlds/postgres#starting-the-world). Under TypeScript the old shape fails the build; in plain JavaScript it does not, and `.start` reads as `undefined` on a promise, so the worker never starts and nothing is logged. Writing `await getWorld()` is also valid on 4.x, so the change can be made before upgrading. |
162
+ | Duplicate step or workflow IDs fail the build | 4.x resolved collisions across non-exported workspace files last-write-wins. If you start encountering build failures after upgrading, rename the colliding functions. |
163
+ | The generated bundles are renamed, and the step route is gone | Only affects apps that wire the output of `workflow build` into their own server instead of using a framework integration. `flow.js` and `webhook.js` are now `flow.mjs` and `webhook.mjs` with named exports only, so a default import resolves to `undefined`. `step.js` became `__step_registrations.mjs`, an internal module that `flow.mjs` imports: delete the `POST /.well-known/workflow/v1/step` route rather than repointing it, because the flow handler now serves step deliveries too. See [Framework integrations](/docs/how-it-works/framework-integrations). |
164
+ | Default trace mode is `linked` | Update dashboards that assume one trace per run, or set `WORKFLOW_TRACE_MODE=continuous`. |
165
+ | The event-creation precondition guard is gone | `WORKFLOW_PRECONDITION_GUARD` no longer exists, and no World in the SDK rejects a write for a stale snapshot. Remove the variable if you set it. A replay that is behind now learns what it missed from the write it makes next instead of from a rejection, and [`PreconditionFailedError`](/docs/api-reference/workflow-errors/precondition-failed-error) remains only for a custom World that would still rather refuse. |
166
+ | Event IDs are slot numbers, not ULIDs | An event ID is now its 1-based position in the run's log (`evnt_00000000000000000000000042`). It is unique only within a run, so pair it with the `runId` as a key, and it carries no timestamp: decoding one yields the Unix epoch rather than a creation time, so read `createdAt` off the event instead. Other entity IDs are unchanged. See [Event IDs](/docs/how-it-works/event-sourcing#event-ids). |
167
+ | A per-run event limit is enforced | The World supplies the ceiling, which is 25,000 events on the Local and Vercel Worlds. A run that reaches it fails with `MAX_EVENTS_EXCEEDED`. Split unbounded loops into [child workflows](/cookbook/advanced/child-workflows). As a fallback, you can tune the ceiling. See [Limits](/docs/configuration/runtime-tuning#limits). |
168
+ | Stream writes flush the first chunk immediately | The leading-edge flush window defaults to `0` instead of 10ms. Restore a window with `streamFlushIntervalMs` or `WORKFLOW_STREAM_FLUSH_INTERVAL_MS`. |
169
+ | The workflow sandbox is stricter about nondeterminism | `WeakRef`, `FinalizationRegistry`, `Atomics.waitAsync`, and async `WebAssembly` compilation are no longer available inside workflow functions, and `crypto.subtle.digest` computes synchronously (same results, deterministic timing). Move code that needs them into a step. |
170
+ | `Date()` without `new` returns a string inside workflow functions | This matches the language spec, and 4.x returned a `Date` object. Use `new Date()` where you need the object. Subclassing `Date` now works, so libraries like `TZDate` keep their identity across the sandbox boundary. |
171
+ | `NestLocalBuilder` moved out of `@workflow/nest` root | Import it from `workflow/nest/builder`, so `WorkflowModule` no longer pulls the build toolchain into the runtime bundle. `NestVercelBuilder` lives at `workflow/nest/vercel-builder`. |
172
+ | `workflow/internal/private` and `@workflow/core/private` removed | These were never public API. The compiler no longer emits imports from them, so regenerate build output rather than importing them yourself. |
173
+ | The legacy trace viewer is gone from `@workflow/web-shared` | Only affects apps embedding the observability UI. `RunTraceView` and `WorkflowTraceViewer` are removed, and `NewTraceViewer` is now `TraceViewer` (module path `trace-viewer`). `Span`, `SpanEvent`, and `Trace` are still exported from the package root. |
174
+
175
+ Runs created on 4.x keep executing on the deployment that created them, so upgrading a deployment does not migrate in-flight runs. One storage caveat is worth knowing about: failed runs stored by `@workflow/world-postgres` before the upgrade read back with `error: undefined`, because the payload lives in the legacy `error` text column rather than `errorJson`.
176
+
177
+ ## If you maintain a World
178
+
179
+ The World interface, which defines the storage, queue, streaming, and analytics contract that a Workflow SDK deployment runs against, also changed in v5. Those changes are not visible from application code. If you implement `World` yourself or maintain a build integration that compiles workflow files, upgrade it alongside the SDK. See [Upgrading a World to v5](/worlds/upgrading-to-v5) for the full interface delta and the contract changes that affect existing implementations. There is a separate skill for that job because none of it applies to application code:
180
+
181
+ ```bash
182
+ npx skills add https://github.com/vercel/workflow --skill migrating-world-v4-to-v5
183
+ ```
184
+
185
+ Applications on the [Vercel](/worlds/vercel), [Local](/worlds/local), and [Postgres](/worlds/postgres) Worlds need nothing from that page: those implementations ship with the SDK and are already on the v5 spec.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "workflow",
3
- "version": "5.0.0-beta.43",
3
+ "version": "5.0.0-beta.44",
4
4
  "description": "Workflow SDK - Build durable, resilient, and observable workflows",
5
5
  "main": "dist/typescript-plugin.cjs",
6
6
  "type": "module",
@@ -59,18 +59,18 @@
59
59
  },
60
60
  "dependencies": {
61
61
  "ms": "2.1.3",
62
- "@workflow/astro": "5.0.0-beta.43",
63
- "@workflow/cli": "5.0.0-beta.43",
64
- "@workflow/core": "5.0.0-beta.43",
65
- "@workflow/errors": "5.0.0-beta.17",
62
+ "@workflow/astro": "5.0.0-beta.44",
63
+ "@workflow/cli": "5.0.0-beta.44",
64
+ "@workflow/core": "5.0.0-beta.44",
65
+ "@workflow/errors": "5.0.0-beta.18",
66
66
  "@workflow/typescript-plugin": "5.0.0-beta.5",
67
- "@workflow/utils": "5.0.0-beta.8",
68
- "@workflow/next": "5.0.0-beta.43",
69
- "@workflow/nest": "5.0.0-beta.43",
70
- "@workflow/nitro": "5.0.0-beta.43",
71
- "@workflow/nuxt": "5.0.0-beta.43",
72
- "@workflow/sveltekit": "5.0.0-beta.43",
73
- "@workflow/rollup": "5.0.0-beta.43"
67
+ "@workflow/utils": "5.0.0-beta.9",
68
+ "@workflow/next": "5.0.0-beta.44",
69
+ "@workflow/nest": "5.0.0-beta.44",
70
+ "@workflow/nitro": "5.0.0-beta.44",
71
+ "@workflow/nuxt": "5.0.0-beta.44",
72
+ "@workflow/sveltekit": "5.0.0-beta.44",
73
+ "@workflow/rollup": "5.0.0-beta.44"
74
74
  },
75
75
  "devDependencies": {
76
76
  "@types/ms": "2.1.0",