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.
- package/README.md +6 -4
- package/dist/internal/builtins.d.ts +4 -4
- package/dist/internal/builtins.js +6 -6
- package/docs/ai/chat-session-modeling.mdx +23 -24
- package/docs/ai/defining-tools.mdx +5 -6
- package/docs/ai/human-in-the-loop.mdx +11 -11
- package/docs/ai/index.mdx +20 -20
- package/docs/ai/message-queueing.mdx +6 -6
- package/docs/ai/meta.json +1 -0
- package/docs/ai/resumable-streams.mdx +28 -28
- package/docs/ai/sleep-and-delays.mdx +9 -9
- package/docs/ai/streaming-updates-from-tools.mdx +4 -4
- package/docs/api-reference/vitest/index.mdx +8 -8
- package/docs/api-reference/workflow/create-hook.mdx +15 -15
- package/docs/api-reference/workflow/create-webhook.mdx +15 -15
- package/docs/api-reference/workflow/define-hook.mdx +10 -10
- package/docs/api-reference/workflow/fatal-error.mdx +2 -2
- package/docs/api-reference/workflow/fetch.mdx +7 -7
- package/docs/api-reference/workflow/get-step-metadata.mdx +2 -2
- package/docs/api-reference/workflow/get-workflow-metadata.mdx +3 -3
- package/docs/api-reference/workflow/get-writable.mdx +7 -7
- package/docs/api-reference/workflow/index.mdx +1 -1
- package/docs/api-reference/workflow/retryable-error.mdx +1 -1
- package/docs/api-reference/workflow/set-attributes.mdx +2 -2
- package/docs/api-reference/workflow/sleep.mdx +3 -3
- package/docs/api-reference/workflow-ai/durable-agent.mdx +42 -42
- package/docs/api-reference/workflow-ai/index.mdx +3 -3
- package/docs/api-reference/workflow-ai/workflow-chat-transport.mdx +28 -28
- package/docs/api-reference/workflow-api/get-hook-by-token.mdx +11 -11
- package/docs/api-reference/workflow-api/get-run.mdx +10 -10
- package/docs/api-reference/workflow-api/index.mdx +2 -4
- package/docs/api-reference/workflow-api/resume-hook.mdx +14 -14
- package/docs/api-reference/workflow-api/resume-webhook.mdx +3 -3
- package/docs/api-reference/workflow-api/start.mdx +16 -15
- package/docs/api-reference/workflow-astro/workflow.mdx +3 -3
- package/docs/api-reference/workflow-errors/entity-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-conflict-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/hook-not-found-error.mdx +8 -8
- package/docs/api-reference/workflow-errors/index.mdx +6 -6
- package/docs/api-reference/workflow-errors/precondition-failed-error.mdx +9 -9
- package/docs/api-reference/workflow-errors/run-expired-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/run-not-supported-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/step-not-registered-error.mdx +5 -5
- package/docs/api-reference/workflow-errors/throttle-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/too-early-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/workflow-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-not-registered-error.mdx +5 -6
- package/docs/api-reference/workflow-errors/workflow-run-cancelled-error.mdx +6 -6
- package/docs/api-reference/workflow-errors/workflow-run-failed-error.mdx +5 -5
- package/docs/api-reference/workflow-errors/workflow-run-not-completed-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-run-not-found-error.mdx +4 -4
- package/docs/api-reference/workflow-errors/workflow-runtime-error.mdx +2 -2
- package/docs/api-reference/workflow-errors/workflow-world-error.mdx +8 -8
- package/docs/api-reference/workflow-globals.mdx +12 -11
- package/docs/api-reference/workflow-nest/configure-workflow-controller.mdx +2 -2
- package/docs/api-reference/workflow-nest/nest-local-builder.mdx +4 -4
- package/docs/api-reference/workflow-nest/workflow-controller.mdx +1 -1
- package/docs/api-reference/workflow-nest/workflow-module.mdx +4 -4
- package/docs/api-reference/workflow-next/with-workflow.mdx +16 -16
- package/docs/api-reference/workflow-nitro/index.mdx +6 -6
- package/docs/api-reference/workflow-nuxt/index.mdx +4 -4
- package/docs/api-reference/workflow-observability/hydrate-data.mdx +5 -5
- package/docs/api-reference/workflow-observability/hydrate-resource-io.mdx +4 -4
- package/docs/api-reference/workflow-observability/index.mdx +6 -8
- package/docs/api-reference/workflow-observability/observability-revivers.mdx +2 -2
- package/docs/api-reference/workflow-observability/parse-class-name.mdx +3 -3
- package/docs/api-reference/workflow-observability/parse-step-name.mdx +4 -4
- package/docs/api-reference/workflow-observability/parse-workflow-name.mdx +4 -4
- package/docs/api-reference/workflow-runtime/create-world.mdx +8 -8
- package/docs/api-reference/workflow-runtime/get-world-handlers.mdx +6 -6
- package/docs/api-reference/workflow-runtime/get-world.mdx +4 -4
- package/docs/api-reference/workflow-runtime/health-check.mdx +1 -1
- package/docs/api-reference/workflow-runtime/index.mdx +2 -4
- package/docs/api-reference/workflow-runtime/set-world.mdx +15 -13
- package/docs/api-reference/workflow-runtime/workflow-entrypoint.mdx +6 -5
- package/docs/api-reference/workflow-runtime/world/analytics.mdx +9 -9
- package/docs/api-reference/workflow-runtime/world/index.mdx +5 -3
- package/docs/api-reference/workflow-runtime/world/queue.mdx +11 -11
- package/docs/api-reference/workflow-runtime/world/storage.mdx +62 -28
- package/docs/api-reference/workflow-runtime/world/streams.mdx +7 -7
- package/docs/api-reference/workflow-serde/index.mdx +1 -1
- package/docs/api-reference/workflow-serde/workflow-deserialize.mdx +2 -2
- package/docs/api-reference/workflow-serde/workflow-serialize.mdx +7 -7
- package/docs/api-reference/workflow-sveltekit/workflow-plugin.mdx +3 -3
- package/docs/api-reference/workflow-vite/workflow.mdx +5 -5
- package/docs/changelog/attributes-mvp.mdx +39 -39
- package/docs/changelog/batched-event-writes.mdx +12 -12
- package/docs/changelog/eager-processing.mdx +63 -63
- package/docs/changelog/index.mdx +3 -3
- package/docs/changelog/lazy-event-creation.md +27 -27
- package/docs/changelog/resilient-resume.mdx +5 -5
- package/docs/changelog/resilient-start.mdx +14 -14
- package/docs/changelog/step-message-ownership.mdx +47 -47
- package/docs/changelog/turbo-mode.md +20 -20
- package/docs/comparisons/index.mdx +13 -13
- package/docs/comparisons/workflow-sdk-vs-aws-agentcore.mdx +15 -15
- package/docs/comparisons/workflow-sdk-vs-aws-step-functions.mdx +12 -12
- package/docs/comparisons/workflow-sdk-vs-cloudflare-workflows.mdx +11 -11
- package/docs/comparisons/workflow-sdk-vs-inngest.mdx +19 -19
- package/docs/comparisons/workflow-sdk-vs-temporal.mdx +23 -23
- package/docs/comparisons/workflow-sdk-vs-trigger-dev.mdx +18 -17
- package/docs/configuration/build-and-diagnostics.mdx +5 -5
- package/docs/configuration/cli-and-web-ui.mdx +4 -4
- package/docs/configuration/runtime-tuning.mdx +86 -23
- package/docs/configuration/worlds.mdx +28 -14
- package/docs/cookbook/advanced/child-workflows.mdx +25 -25
- package/docs/cookbook/advanced/publishing-libraries.mdx +40 -40
- package/docs/cookbook/advanced/serializable-steps.mdx +21 -21
- package/docs/cookbook/advanced/upgrading-workflows.mdx +31 -31
- package/docs/cookbook/agent-patterns/agent-cancellation.mdx +20 -20
- package/docs/cookbook/agent-patterns/human-in-the-loop.mdx +22 -22
- package/docs/cookbook/common-patterns/batching.mdx +14 -14
- package/docs/cookbook/common-patterns/idempotency.mdx +9 -9
- package/docs/cookbook/common-patterns/rate-limiting.mdx +3 -3
- package/docs/cookbook/common-patterns/saga.mdx +19 -19
- package/docs/cookbook/common-patterns/scheduling.mdx +23 -23
- package/docs/cookbook/common-patterns/sequential-and-parallel.mdx +26 -26
- package/docs/cookbook/common-patterns/timeouts.mdx +23 -23
- package/docs/cookbook/common-patterns/webhooks.mdx +6 -6
- package/docs/cookbook/common-patterns/workflow-composition.mdx +19 -19
- package/docs/cookbook/index.mdx +22 -22
- package/docs/cookbook/integrations/ai-sdk.mdx +43 -41
- package/docs/cookbook/integrations/chat-sdk.mdx +34 -34
- package/docs/cookbook/integrations/sandbox.mdx +46 -46
- package/docs/deploying.mdx +15 -15
- package/docs/errors/abort-signal-timeout-in-workflow.mdx +12 -12
- package/docs/errors/corrupted-event-log.mdx +11 -11
- package/docs/errors/deployment-mismatch.mdx +14 -14
- package/docs/errors/fetch-in-workflow.mdx +8 -8
- package/docs/errors/hook-conflict.mdx +11 -11
- package/docs/errors/index.mdx +1 -1
- package/docs/errors/node-js-module-in-workflow.mdx +5 -5
- package/docs/errors/replay-divergence.mdx +2 -2
- package/docs/errors/runtime-decryption-failed.mdx +12 -12
- package/docs/errors/serialization-failed.mdx +40 -12
- package/docs/errors/start-invalid-workflow-function.mdx +5 -5
- package/docs/errors/step-executed-multiple-times.mdx +2 -2
- package/docs/errors/step-not-registered.mdx +5 -5
- package/docs/errors/timeout-in-workflow.mdx +8 -8
- package/docs/errors/webhook-invalid-respond-with-value.mdx +18 -18
- package/docs/errors/webhook-response-not-sent.mdx +16 -16
- package/docs/errors/workflow-not-registered.mdx +5 -5
- package/docs/foundations/cancellation.mdx +31 -31
- package/docs/foundations/errors-and-retries.mdx +42 -11
- package/docs/foundations/hooks.mdx +35 -35
- package/docs/foundations/idempotency.mdx +9 -9
- package/docs/foundations/serialization.mdx +21 -22
- package/docs/foundations/starting-workflows.mdx +36 -37
- package/docs/foundations/streaming.mdx +46 -41
- package/docs/foundations/versioning.mdx +3 -3
- package/docs/foundations/workflows-and-steps.mdx +9 -9
- package/docs/getting-started/astro.mdx +16 -16
- package/docs/getting-started/express.mdx +8 -8
- package/docs/getting-started/fastify.mdx +8 -8
- package/docs/getting-started/hono.mdx +8 -8
- package/docs/getting-started/nestjs.mdx +18 -17
- package/docs/getting-started/next.mdx +11 -11
- package/docs/getting-started/nitro.mdx +16 -16
- package/docs/getting-started/nuxt.mdx +8 -8
- package/docs/getting-started/python.mdx +4 -4
- package/docs/getting-started/react-router/v7.mdx +1 -1
- package/docs/getting-started/react-router/v8.mdx +1 -1
- package/docs/getting-started/sveltekit.mdx +14 -14
- package/docs/getting-started/tanstack-start.mdx +12 -12
- package/docs/getting-started/vite.mdx +8 -8
- package/docs/how-it-works/cancellation.mdx +62 -62
- package/docs/how-it-works/code-transform.mdx +66 -54
- package/docs/how-it-works/encryption.mdx +25 -21
- package/docs/how-it-works/event-sourcing.mdx +53 -35
- package/docs/how-it-works/framework-integrations.mdx +12 -12
- package/docs/how-it-works/understanding-directives.mdx +21 -21
- package/docs/internal/index.mdx +6 -6
- package/docs/internal/nitro-native-build.mdx +2 -2
- package/docs/internal/nitro-web-ui.mdx +4 -4
- package/docs/internal/serializable-abort-controller.mdx +7 -7
- package/docs/observability/attributes.mdx +3 -3
- package/docs/observability/index.mdx +14 -10
- package/docs/observability/tracing.mdx +10 -10
- package/docs/testing/index.mdx +33 -33
- package/docs/testing/server-based.mdx +10 -10
- package/docs/whats-new.mdx +185 -0
- package/package.json +12 -12
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Workflow SDK vs AWS Step Functions
|
|
3
|
-
description: How the Workflow SDK compares to AWS Step Functions
|
|
3
|
+
description: How the Workflow SDK compares to AWS Step Functions, including plain TypeScript control flow versus declarative Amazon States Language JSON and a concept-mapping migration guide.
|
|
4
4
|
type: conceptual
|
|
5
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
6
|
prerequisites:
|
|
@@ -11,7 +11,7 @@ related:
|
|
|
11
11
|
- /worlds/vercel
|
|
12
12
|
---
|
|
13
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)
|
|
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 authoring model is the main contrast with the Workflow SDK: you assemble a state machine (JSON or a visual editor) instead of writing plain control-flow code.
|
|
15
15
|
|
|
16
16
|
<Callout type="info">
|
|
17
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.
|
|
@@ -21,7 +21,7 @@ related:
|
|
|
21
21
|
|
|
22
22
|
| | Workflow SDK | AWS Step Functions |
|
|
23
23
|
| --- | --- | --- |
|
|
24
|
-
| **Authoring** | Plain TypeScript: `"use workflow"` orchestrators calling `"use step"` functions | **Declarative ASL JSON** (or Workflow Studio visual editor / CDK)
|
|
24
|
+
| **Authoring** | Plain TypeScript: `"use workflow"` orchestrators calling `"use step"` functions | **Declarative ASL JSON** (or Workflow Studio visual editor / CDK), not plain code |
|
|
25
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
26
|
| **Control flow** | `await`, `if`/`switch`, `Promise.all`, `try/catch` | `Task` / `Choice` / `Wait` / `Parallel` / `Map` states wired with `Next` |
|
|
27
27
|
| **Where it runs** | Your platform (Vercel managed or self-host) | AWS-managed; tasks run in Lambda or 200+ integrated AWS services |
|
|
@@ -29,18 +29,18 @@ related:
|
|
|
29
29
|
| **Human-in-the-loop** | `createHook()` / `createWebhook()` | `.waitForTaskToken` callback (Standard only) |
|
|
30
30
|
| **Streaming** | Native durable, resumable streaming to clients | No native client streaming |
|
|
31
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
|
|
32
|
+
| **Portability** | Apache-2.0; runs anywhere Node runs | Proprietary and AWS-only; ASL is AWS-specific, resulting in high lock-in |
|
|
33
33
|
| **Pricing** | SDK free; pay your platform | **Standard:** $0.025 / 1K state transitions. **Express:** $1 / M requests + GB-second duration |
|
|
34
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
35
|
| **AI** | `WorkflowAgent` in the AI SDK; durable streaming | Bedrock integration + a preview AgentCore "InvokeHarness" task; no native client streaming |
|
|
36
36
|
|
|
37
|
-
**What the limits mean in practice:**
|
|
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
38
|
|
|
39
39
|
## Code vs. JSON
|
|
40
40
|
|
|
41
|
-
|
|
41
|
+
In Step Functions, even "call one Lambda" requires a state-machine shell, and ASL states (`Choice`, `Wait`, `Parallel`, `Map`) express the orchestration logic. In the Workflow SDK, ordinary TypeScript handles orchestration: transitions are `await`, branches are `if`, parallelism is `Promise.all`, and error handling is `try/catch`. This 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
42
|
|
|
43
|
-
The
|
|
43
|
+
The tradeoff is that Step Functions' optimized service integrations call AWS services (DynamoDB, SQS, EventBridge, Bedrock, `ecs:runTask.sync`, and others) declaratively. In the Workflow SDK, these become ordinary SDK calls inside `"use step"` functions, and you own the credentials, retries, and any polling.
|
|
44
44
|
|
|
45
45
|
## Migrating from Step Functions
|
|
46
46
|
|
|
@@ -53,10 +53,10 @@ This guide assumes **Standard** workflows. Express workflows have different sema
|
|
|
53
53
|
| Choice state | `if` / `else` / `switch` | Native control flow. |
|
|
54
54
|
| Wait state | `sleep()` | `sleep('1m')` or `sleep(date)`. |
|
|
55
55
|
| Parallel state | `Promise.all()` | Standard concurrency. |
|
|
56
|
-
| Map state | `for` loop / bounded `Promise.all` (e.g. `p-limit`) /
|
|
57
|
-
| Retry / Catch | `maxRetries`, `RetryableError`, `FatalError`; `try/catch` for compensation | Retry logic moves to step boundaries. |
|
|
56
|
+
| Map state | `for` loop / bounded `Promise.all` (e.g. `p-limit`) / [`start()`](/docs/foundations/starting-workflows) per item for large fan-out | Match the original concurrency mode. |
|
|
57
|
+
| Retry / Catch (`MaxAttempts`, `BackoffRate`, `IntervalSeconds`) | `maxRetries`, `RetryableError`, `FatalError`; `try/catch` for compensation | Retry logic moves to step boundaries; backoff curves use `retryAfter`. See [Errors & Retrying](/docs/foundations/errors-and-retries#advanced-example). |
|
|
58
58
|
| `.waitForTaskToken` | `createHook()` / `createWebhook()` | Hooks for typed signals; webhooks for HTTP. |
|
|
59
|
-
| Child state machine (`StartExecution`) |
|
|
59
|
+
| Child state machine (`StartExecution`) | Call [`start()`](/docs/foundations/starting-workflows) directly from the workflow | Child runs are tagged with `$parentRunId` / `$rootRunId` automatically. |
|
|
60
60
|
|
|
61
61
|
A single `Task` state and its Lambda collapse into two directive-tagged functions:
|
|
62
62
|
|
|
@@ -74,7 +74,7 @@ async function loadOrder(id: string) {
|
|
|
74
74
|
}
|
|
75
75
|
```
|
|
76
76
|
|
|
77
|
-
A `.waitForTaskToken` callback becomes a hook
|
|
77
|
+
A `.waitForTaskToken` callback becomes a hook without an SQS queue, task token, or callback Lambda:
|
|
78
78
|
|
|
79
79
|
```typescript title="workflows/refund.ts"
|
|
80
80
|
import { createHook } from 'workflow';
|
|
@@ -103,7 +103,7 @@ Each row is a Step Functions capability the Workflow SDK does not replicate one-
|
|
|
103
103
|
| Step Functions feature | How to cover it with the Workflow SDK |
|
|
104
104
|
| --- | --- |
|
|
105
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
|
|
106
|
+
| Distributed Map (up to 10,000 concurrent children, S3 item sources) | Fan out with `start()` per item directly from the workflow, then bound concurrency with `p-limit` |
|
|
107
107
|
| Optimized AWS service integrations | Become ordinary SDK calls inside steps; `.sync` waits become explicit polling or hooks |
|
|
108
108
|
| Per-state IAM roles | Steps share the deployment's credentials; scope secrets at deploy time |
|
|
109
109
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Workflow SDK vs Cloudflare Workflows
|
|
3
|
-
description: How the Workflow SDK compares to 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 differently.
|
|
4
4
|
type: conceptual
|
|
5
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
6
|
prerequisites:
|
|
@@ -11,7 +11,7 @@ related:
|
|
|
11
11
|
- /worlds/building-a-world
|
|
12
12
|
---
|
|
13
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
|
|
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 because both persist progress and replay to survive failures. The differences in **versioning safety, encryption, and portability** are the deciding factors.
|
|
15
15
|
|
|
16
16
|
<Callout type="info">
|
|
17
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.
|
|
@@ -24,33 +24,33 @@ related:
|
|
|
24
24
|
| **Category** | Open-source durable-functions SDK; portable backends | Durable execution engine, hosted on Cloudflare |
|
|
25
25
|
| **Durability model** | Event log + deterministic replay | Step-result **memoization** in SQLite-backed Durable Objects + deterministic re-calculation ("game-loop") |
|
|
26
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
|
|
28
|
-
| **Versioning** | Runs pinned to their immutable deployment
|
|
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, making them safe by default | **No version pinning**; running instances resume on the *latest* deployed code, and changing step names/order can desync the cached replay. No patching API |
|
|
29
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
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)
|
|
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), providing the strongest cold-start and edge story |
|
|
32
32
|
| **Portability** | Apache-2.0; World abstraction; self-hostable | Engine proprietary; tied to Durable Objects; **highest lock-in** of these tools |
|
|
33
33
|
| **Pricing** | SDK free; pay your platform | Workers Standard: requests + CPU-time + storage + per-step ($0.80 / 100K steps); idle/sleep not billed |
|
|
34
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
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
|
|
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
37
|
|
|
38
38
|
## Versioning: pinned vs. live code
|
|
39
39
|
|
|
40
|
-
Both engines replay, so changing code mid-run is the key hazard
|
|
40
|
+
Both engines replay, so changing code mid-run is the key hazard. They take opposite approaches:
|
|
41
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
|
|
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, only the documented "[Rules of Workflows](https://developers.cloudflare.com/workflows/build/rules-of-workflows/)" you must follow manually.
|
|
43
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
44
|
|
|
45
45
|
## Encryption and portability
|
|
46
46
|
|
|
47
|
-
Cloudflare encrypts Durable Object data at rest with Cloudflare-managed keys, but there is no application-level / end-to-end encryption
|
|
47
|
+
Cloudflare encrypts Durable Object data at rest with Cloudflare-managed keys, but there is no application-level / end-to-end encryption or customer-managed-key option. The platform can view payloads. The Workflow SDK encrypts each run's inputs, outputs, step I/O, and streams with a per-run AES-256-GCM key.
|
|
48
48
|
|
|
49
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
50
|
|
|
51
51
|
## Where Cloudflare leads
|
|
52
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
|
|
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, a 100K concurrency ceiling, and [multi-region support](/worlds/vercel#multi-region).
|
|
54
54
|
|
|
55
55
|
## Moving from Cloudflare Workflows
|
|
56
56
|
|
|
@@ -62,7 +62,7 @@ There's no automated migration skill for Cloudflare specifically, but the mappin
|
|
|
62
62
|
| `step.do(name, cb)` | `"use step"` function called with `await` |
|
|
63
63
|
| `step.sleep` / `step.sleepUntil` | `sleep('1h')` / `sleep(date)` |
|
|
64
64
|
| `step.waitForEvent` | `createHook()` / `createWebhook()` |
|
|
65
|
-
| Per-step `retries` config | `maxRetries
|
|
65
|
+
| Per-step `retries` config (`limit`, `delay`, `backoff`) | `maxRetries` caps attempts; any backoff curve via [`RetryableError`](/docs/api-reference/workflow/retryable-error)'s `retryAfter` derived from [`getStepMetadata().attempt`](/docs/api-reference/workflow/get-step-metadata); `FatalError` stops retries. See [Errors & Retrying](/docs/foundations/errors-and-retries#advanced-example) |
|
|
66
66
|
| `env.MY_WORKFLOW.create(...)` binding | `start(workflow, [args])` from your app |
|
|
67
67
|
|
|
68
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.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Workflow SDK vs Inngest
|
|
3
|
-
description: How the Workflow SDK compares to 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
4
|
type: conceptual
|
|
5
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
6
|
prerequisites:
|
|
@@ -11,10 +11,10 @@ related:
|
|
|
11
11
|
- /docs/ai
|
|
12
12
|
---
|
|
13
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
|
|
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
15
|
|
|
16
16
|
<Callout type="info">
|
|
17
|
-
**Choose the Workflow SDK** when you want orchestration and execution co-located (no per-step HTTP round
|
|
17
|
+
**Choose the Workflow SDK** when you want orchestration and execution co-located (no per-step HTTP round trips), deployment-pinned versioning, and a supported open-source self-hosting path. **Choose Inngest** when an event-bus model fits your architecture and you want built-in flow controls for concurrency, throttling, debounce, batching, and priority.
|
|
18
18
|
</Callout>
|
|
19
19
|
|
|
20
20
|
## At a glance
|
|
@@ -22,34 +22,34 @@ related:
|
|
|
22
22
|
| | Workflow SDK | Inngest |
|
|
23
23
|
| --- | --- | --- |
|
|
24
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)
|
|
25
|
+
| **Durability model** | Event log + deterministic replay | **Step-result memoization** (each `step.run` runs once; completed steps are skipped), not whole-function replay |
|
|
26
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
|
|
28
|
-
| **Languages** | TypeScript /
|
|
29
|
-
| **Versioning** | Runs pinned to immutable deployment | Tracked by step-ID hashes
|
|
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
|
|
31
|
-
| **Security** | Zero-config per-run E2E encryption by default; platform security is per
|
|
32
|
-
| **Portability** | Apache-2.0; World abstraction; **self-host supported** | Engine open source (
|
|
27
|
+
| **Where execution runs** | Orchestration + execution co-located on your platform | **Your code runs on your infrastructure**; Inngest invokes it per step over HTTP (Serve) or a persistent worker connection (Connect, in public beta) |
|
|
28
|
+
| **Languages** | TypeScript / JavaScript (Python beta) | TypeScript; Python and 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 end-to-end (E2E) encryption by default; platform security is per World (the Vercel World inherits Vercel's security posture) | Runs on your infrastructure; signed requests; first-party E2E encryption middleware (TypeScript and Python); SOC 2 Type II, HIPAA add-on |
|
|
32
|
+
| **Portability** | Apache-2.0; World abstraction; **self-host supported** | Engine open source (Server Side Public License); self-host via single Go binary + Postgres, but **self-hosting is community/best-effort**: no support service-level agreement, and the `inngest start` binary is Beta (the hosted service is the default) |
|
|
33
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;
|
|
34
|
+
| **Limits** | 50 MB payload; 2 GB/run; 10,000 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
35
|
|
|
36
|
-
**What the limits mean in practice
|
|
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 it can consume 1,000 steps per function; a single large language model response can approach the 4 MiB step-payload cap; and an accumulated conversation or context can outgrow 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
37
|
|
|
38
38
|
## Topology: co-located vs. invoked-over-HTTP
|
|
39
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
|
|
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 infrastructure for portability and data locality, but adds a network round trip per step. This overhead matters for workflows with many small sequential steps. The Workflow SDK co-locates orchestration and execution on one platform, so steps don't require a per-step HTTP request.
|
|
41
41
|
|
|
42
|
-
Triggering differs
|
|
42
|
+
Triggering also differs. Inngest is event-driven (publishers `send` events; functions subscribe), which supports loosely coupled fan-out. The Workflow SDK's `start()` imports the workflow function directly, providing tighter coupling and stronger type safety. For event-bus-style fan-out, wrap `start()` in a shared publisher.
|
|
43
43
|
|
|
44
44
|
## Versioning
|
|
45
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
|
|
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
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
|
|
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
49
|
|
|
50
50
|
## AI agents
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
Inngest offers `step.ai.wrap()` (wrap Vercel AI SDK calls as durable steps), **AgentKit** (a multi-agent framework with Model Context Protocol (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). AgentKit fits event-driven applications that need an integrated agent framework. The Workflow SDK fits applications that need the agent loop to be a durable workflow with streaming built into the runtime.
|
|
53
53
|
|
|
54
54
|
## Migrating from Inngest
|
|
55
55
|
|
|
@@ -59,9 +59,9 @@ Both are strong here. Inngest offers `step.ai.wrap()` (wrap Vercel AI SDK calls
|
|
|
59
59
|
| `step.run()` | `"use step"` function | Named async function with Node.js access. |
|
|
60
60
|
| `step.sleep()` / `step.sleepUntil()` | `sleep('5m')` / `sleep(date)` | Import from `workflow`. |
|
|
61
61
|
| `step.waitForEvent()` | `createHook()` / `createWebhook()` | Token encodes the routing; no event schema. |
|
|
62
|
-
| `step.invoke()` | `
|
|
62
|
+
| `step.invoke()` | [`start()`](/docs/foundations/starting-workflows) called directly from the workflow | Spawn a child run. |
|
|
63
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. |
|
|
64
|
+
| Retry config (`retries`) / `RetryAfterError` | `maxRetries`, `RetryableError`, `FatalError` | Retries live at the step boundary. For custom backoff via `retryAfter`, see [Errors & Retrying](/docs/foundations/errors-and-retries#customize-retry-behavior). |
|
|
65
65
|
| `step.realtime.publish()` / Realtime | `getWritable()` / named streams | Clients read from the stream. |
|
|
66
66
|
|
|
67
67
|
The `createFunction` factory collapses into a plain exported function:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Workflow SDK vs Temporal
|
|
3
|
-
description: How the Workflow SDK compares to 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
4
|
type: conceptual
|
|
5
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
6
|
prerequisites:
|
|
@@ -12,10 +12,10 @@ related:
|
|
|
12
12
|
- /worlds/vercel
|
|
13
13
|
---
|
|
14
14
|
|
|
15
|
-
[Temporal](https://temporal.io) is
|
|
15
|
+
[Temporal](https://temporal.io) is a durable-execution platform with seven language SDKs and large-scale production use. Temporal and the Workflow SDK share the same core model of durable orchestration through event-sourced replay. The operational differences are **where your code runs, how you version it, and how it streams to clients.**
|
|
16
16
|
|
|
17
17
|
<Callout type="info">
|
|
18
|
-
**Choose the Workflow SDK** when you want durable execution inside your existing TypeScript app with
|
|
18
|
+
**Choose the Workflow SDK** when you want durable execution inside your existing TypeScript app with no additional infrastructure to operate, deployment-pinned versioning, and native streaming for AI apps. **Choose Temporal** when you need SDKs for languages such as Go and Java, want a self-hostable control plane you own, or are standardizing a large organization on one orchestration backend across many languages.
|
|
19
19
|
</Callout>
|
|
20
20
|
|
|
21
21
|
## At a glance
|
|
@@ -23,22 +23,22 @@ related:
|
|
|
23
23
|
| | Workflow SDK | Temporal |
|
|
24
24
|
| --- | --- | --- |
|
|
25
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
|
|
27
|
-
| **Languages** | TypeScript /
|
|
28
|
-
| **Where execution runs** | Orchestration + execution + observability co-located on your platform; private networking and E2E encryption
|
|
29
|
-
| **Versioning** | Runs pinned to their immutable deployment
|
|
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"
|
|
31
|
-
| **Security** | Zero-config per-run AES-256-GCM E2E encryption by default; platform security is per
|
|
32
|
-
| **Performance** | No-penalty resume; serverless scale-to-zero (true suspension); up to
|
|
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 / JavaScript (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 end-to-end (E2E) encryption included 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 infrastructure (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 100,000 concurrency on Vercel | Self-managed workers are long-running; Cloud namespace default 500 actions/sec (auto-scales) |
|
|
33
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
|
|
35
|
-
| **Limits** | No run/sleep cap;
|
|
34
|
+
| **Pricing** | SDK free; pay your platform (Vercel: events + data) or only your infrastructure if self-hosted | Self-host = free software; Temporal Cloud bills per Action (from $50 per million) + storage |
|
|
35
|
+
| **Limits** | No run/sleep cap; 10,000 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
36
|
|
|
37
|
-
**What the limits mean in practice
|
|
37
|
+
**What the limits mean in practice**: Temporal caps payloads at 2 MB and event history at 51,200 events. A model context, tool transcript, or embedding batch that exceeds 2 MB requires external blob storage and claim-check plumbing. Long agent loops must use 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, and no run or sleep caps) provide more space for contexts in the run itself.
|
|
38
38
|
|
|
39
39
|
## The biggest difference: what you operate
|
|
40
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
|
|
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 and Google Cloud Private Service Connect are available as same-region options). To make encrypted payloads readable in the Web UI, you must run a **Codec Server**.
|
|
42
42
|
|
|
43
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
44
|
|
|
@@ -46,14 +46,14 @@ With the Workflow SDK on Vercel, orchestration, execution, and observability are
|
|
|
46
46
|
|
|
47
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
48
|
|
|
49
|
-
- **Temporal
|
|
50
|
-
- **Workflow SDK
|
|
49
|
+
- **Temporal**: Editing a workflow can produce a non-determinism error that breaks or stalls open executions. You can evolve workflows with **patch APIs** (`patched()` / `GetVersion()`, which accumulate patch branches) or **Worker Versioning** (Build IDs / Worker Deployments pin workflows to a build and keep the old worker fleet running until it drains). You must manage this process 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 because 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). This model requires no patch branches or draining worker fleets.
|
|
51
51
|
|
|
52
52
|
## AI agents and streaming
|
|
53
53
|
|
|
54
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
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
|
|
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
57
|
|
|
58
58
|
## Migrating from Temporal
|
|
59
59
|
|
|
@@ -66,11 +66,12 @@ The model maps closely. Keep your orchestration logic; drop the workers, task qu
|
|
|
66
66
|
| Worker + Task Queue | Managed execution | No worker fleet or polling loop to operate. |
|
|
67
67
|
| Signal | `createHook()` / `createWebhook()` | Hooks for typed resume signals; webhooks for HTTP callbacks. |
|
|
68
68
|
| Query | `getWritable({ namespace: 'status' })` stream | Stream status durably; clients read the stream instead of polling. |
|
|
69
|
-
| Child Workflow |
|
|
70
|
-
| Activity retry policy | `maxRetries`, `RetryableError`, `FatalError` | Retries live at the step boundary. |
|
|
69
|
+
| Child Workflow | Call [`start()`](/docs/foundations/starting-workflows) directly from the workflow | Child runs are tagged with `$parentRunId` / `$rootRunId` automatically. |
|
|
70
|
+
| Activity retry policy | `maxRetries`, `RetryableError`, `FatalError` | Retries live at the step boundary. See [Errors & Retrying](/docs/foundations/errors-and-retries). |
|
|
71
|
+
| Search attributes / visibility queries | [`setAttributes()`](/docs/api-reference/workflow/set-attributes) / `attributes` option on `start()` | Filter runs by `key=value`. See [Attributes](/docs/observability/attributes). |
|
|
71
72
|
| Event History | Workflow event log / run timeline | Same durable replay; built-in observability UI. |
|
|
72
73
|
|
|
73
|
-
A minimal translation
|
|
74
|
+
A minimal translation, where the orchestrator loses `proxyActivities` and becomes plain TypeScript:
|
|
74
75
|
|
|
75
76
|
```typescript title="workflows/order.ts"
|
|
76
77
|
export async function processOrder(orderId: string) {
|
|
@@ -85,7 +86,7 @@ async function chargePayment(orderId: string) {
|
|
|
85
86
|
}
|
|
86
87
|
```
|
|
87
88
|
|
|
88
|
-
Signals become hooks
|
|
89
|
+
Signals become hooks, where one `createHook()` + `await` replaces a signal definition, handler, and `condition()` guard:
|
|
89
90
|
|
|
90
91
|
```typescript title="workflows/refund.ts"
|
|
91
92
|
import { createHook } from 'workflow';
|
|
@@ -114,9 +115,8 @@ Each row is a Temporal capability the Workflow SDK does not replicate one-to-one
|
|
|
114
115
|
|
|
115
116
|
| Temporal feature | How to cover it with the Workflow SDK |
|
|
116
117
|
| --- | --- |
|
|
117
|
-
| Search attributes / visibility queries | Filter runs by status and timestamps via `getRun()` and the observability UI |
|
|
118
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
|
-
|
|
|
119
|
+
| Declarative retry policy (`backoffCoefficient`, `nonRetryableErrorTypes`, `maximumAttempts`) | The Workflow SDK expresses the same policies idiomatically in code instead of a config object: cap attempts with [`maxRetries`](/docs/foundations/errors-and-retries#default-retrying), mark errors non-retryable with [`FatalError`](/docs/api-reference/workflow/fatal-error), and derive any backoff curve from [`getStepMetadata().attempt`](/docs/api-reference/workflow/get-step-metadata) via [`RetryableError`](/docs/api-reference/workflow/retryable-error)'s `retryAfter`. See the [exponential backoff example](/docs/foundations/errors-and-retries#advanced-example). |
|
|
120
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
121
|
|
|
122
122
|
---
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Workflow SDK vs trigger.dev
|
|
3
|
-
description: How the Workflow SDK compares to trigger.dev
|
|
3
|
+
description: How the Workflow SDK compares to trigger.dev, including deterministic event-log replay versus CRIU process checkpoint/restore and a concept-mapping migration guide.
|
|
4
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.
|
|
5
|
+
summary: trigger.dev achieves durability by snapshotting the process with Checkpoint/Restore in Userspace (CRIU), so code has no determinism constraints. The Workflow SDK uses event-log replay and runs in your existing app.
|
|
6
6
|
prerequisites:
|
|
7
7
|
- /docs/foundations/workflows-and-steps
|
|
8
8
|
related:
|
|
@@ -11,10 +11,10 @@ related:
|
|
|
11
11
|
- /docs/ai
|
|
12
12
|
---
|
|
13
13
|
|
|
14
|
-
[trigger.dev](https://trigger.dev) is an open-source, TypeScript-first durable task platform.
|
|
14
|
+
[trigger.dev](https://trigger.dev) is an open-source, TypeScript-first durable task platform. Instead of replaying code, it **snapshots the whole process** with Checkpoint/Restore in Userspace (CRIU) at each wait point and restores it later. This design drives most of the differences with the Workflow SDK.
|
|
15
15
|
|
|
16
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
|
|
17
|
+
**Choose the Workflow SDK** when you want durable orchestration that runs in your existing app, a portable open-source backend you can self-host, TypeScript and Python, and broad framework support. **Choose trigger.dev** when you want a managed task platform with no determinism constraints and use only TypeScript.
|
|
18
18
|
</Callout>
|
|
19
19
|
|
|
20
20
|
## At a glance
|
|
@@ -22,30 +22,30 @@ related:
|
|
|
22
22
|
| | Workflow SDK | trigger.dev |
|
|
23
23
|
| --- | --- | --- |
|
|
24
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)
|
|
25
|
+
| **Durability model** | Event log + **deterministic replay** (workflow body must be deterministic) | **Process checkpoint/restore (CRIU)**: snapshots memory, CPU, and file descriptors; **no determinism constraints**, code runs as-is |
|
|
26
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 /
|
|
27
|
+
| **Languages** | TypeScript / JavaScript (Python beta) | **TypeScript / JavaScript only** |
|
|
28
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
|
|
30
|
-
| **AI
|
|
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 and streaming** | `WorkflowAgent` in the AI SDK; native resumable streaming | AI SDK tools, native `useChat` transport, resumable Realtime, durable multi-turn Sessions, human-in-the-loop (HITL) via `wait.forToken` |
|
|
31
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/
|
|
32
|
+
| **Portability** | Apache-2.0; World abstraction; runs anywhere Node runs | Apache-2.0; self-host on Docker/Kubernetes, but CRIU needs a compatible host (heavier than plain Docker); TypeScript-only |
|
|
33
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
|
|
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 maximum run lifetime; CPU-time-based maximum duration |
|
|
35
35
|
|
|
36
|
-
**What the limits mean in practice
|
|
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 maximum run time 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
37
|
|
|
38
38
|
## The core difference: checkpoint/restore vs. replay
|
|
39
39
|
|
|
40
|
-
trigger.dev freezes the entire
|
|
40
|
+
trigger.dev freezes the entire operating system 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
41
|
|
|
42
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
43
|
|
|
44
|
-
Notably, **both pin runs to a version** so deploys never corrupt in-flight work
|
|
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
45
|
|
|
46
46
|
## AI agents
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
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 workflows (trigger.dev's `wait.forToken` and the Workflow SDK's hooks). Key differences are language support (trigger.dev is TypeScript-only; the Workflow SDK adds Python) and whether the agent runs in your app or on a dedicated platform.
|
|
49
49
|
|
|
50
50
|
## Migrating from trigger.dev
|
|
51
51
|
|
|
@@ -56,12 +56,13 @@ Both invest heavily in AI. trigger.dev offers AI SDK tool wrapping, a native `us
|
|
|
56
56
|
| Inline `run` body | `"use step"` functions | Side effects move into named steps. |
|
|
57
57
|
| `wait.for` / `wait.until` | `sleep('5m')` / `sleep(date)` | Import from `workflow`. |
|
|
58
58
|
| `wait.forToken({ timeout })` | `createHook()` + `Promise.race` with `sleep()` | Hooks carry a typed token. |
|
|
59
|
-
| `triggerAndWait()` | `
|
|
59
|
+
| `triggerAndWait()` | [`start()`](/docs/foundations/starting-workflows) called directly from the workflow, then await the returned `Run` | Spawn + collect. |
|
|
60
60
|
| `batch.triggerAndWait()` | `Promise.all` over collected `Run` handles | Standard concurrency. |
|
|
61
61
|
| `metadata.stream()` / Realtime | `getWritable()` / named streams | Clients read from the stream. |
|
|
62
|
+
| Run tags / `metadata.set()` | [`setAttributes()`](/docs/api-reference/workflow/set-attributes) / `attributes` option on `start()` | Filter runs by `key=value`. See [Attributes](/docs/observability/attributes). |
|
|
62
63
|
| `AbortTaskRunError` | `FatalError` | Stops retries immediately. |
|
|
63
64
|
|
|
64
|
-
The `task()` factory collapses into a plain function
|
|
65
|
+
The `task()` factory collapses into a plain function, and because the workflow body is replayed, move side effects into steps:
|
|
65
66
|
|
|
66
67
|
```typescript title="workflows/order.ts"
|
|
67
68
|
export async function processOrder(orderId: string) {
|
|
@@ -78,7 +79,7 @@ async function loadOrder(orderId: string) {
|
|
|
78
79
|
```
|
|
79
80
|
|
|
80
81
|
<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
|
|
82
|
+
trigger.dev's `run` body has full Node.js access. The Workflow SDK's `"use workflow"` body runs in a sandboxed virtual machine (VM). Side effects (`fetch`, `Date.now()`, `Math.random()`, and database access) must live inside `"use step"` functions. Orchestration stays in the workflow body.
|
|
82
83
|
</Callout>
|
|
83
84
|
|
|
84
85
|
<Callout type="info">
|
|
@@ -40,7 +40,7 @@ Accepted values:
|
|
|
40
40
|
|
|
41
41
|
- Default: disabled
|
|
42
42
|
- Set `1` to expose the workflow manifest at `/.well-known/workflow/v1/manifest.json`.
|
|
43
|
-
- Useful for
|
|
43
|
+
- Useful for end-to-end tests and tools that need to discover workflows over HTTP.
|
|
44
44
|
|
|
45
45
|
## Discovery
|
|
46
46
|
|
|
@@ -49,8 +49,8 @@ Accepted values:
|
|
|
49
49
|
- Framework option: `discoverWorkflowsInNodeModules` where supported
|
|
50
50
|
- Default: enabled
|
|
51
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
|
|
53
|
-
- The SDK's own runtime serde classes (
|
|
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 (for example, `Run`) stay registered because they are reached through a seeded entry point, and imports *within* `node_modules` are still followed.
|
|
54
54
|
- Explicit framework config wins over this environment variable.
|
|
55
55
|
|
|
56
56
|
## Development diagnostics
|
|
@@ -59,12 +59,12 @@ Accepted values:
|
|
|
59
59
|
|
|
60
60
|
- Default: disabled
|
|
61
61
|
- Set `1` to log workflow rebuild activity during `next dev`.
|
|
62
|
-
- Useful for diagnosing watch and HMR issues.
|
|
62
|
+
- Useful for diagnosing watch and hot module replacement (HMR) issues.
|
|
63
63
|
|
|
64
64
|
### `WORKFLOW_DEV_WATCH_IGNORED_PATHS`
|
|
65
65
|
|
|
66
66
|
- Default: unset
|
|
67
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 (
|
|
68
|
+
- Each entry is matched as a substring of the absolute path (for example, `/fixtures/,/generated/`).
|
|
69
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
70
|
- Useful when a project has thousands of non-ignored directories and `next dev` fails with `EMFILE: too many open files, watch`.
|
|
@@ -8,7 +8,7 @@ related:
|
|
|
8
8
|
- /docs/configuration/worlds
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
The
|
|
11
|
+
The Workflow CLI uses flags first, then environment variables, then defaults or local inference.
|
|
12
12
|
|
|
13
13
|
Vercel project and auth settings can often be inferred from `.vercel/project.json` and your Vercel CLI login.
|
|
14
14
|
|
|
@@ -57,7 +57,7 @@ Vercel project and auth settings can often be inferred from `.vercel/project.jso
|
|
|
57
57
|
|
|
58
58
|
- Environment variable: none
|
|
59
59
|
- Default: disabled
|
|
60
|
-
- Opens the relevant dashboard or web UI instead of printing terminal output.
|
|
60
|
+
- Opens the relevant dashboard or web user interface (UI) instead of printing terminal output.
|
|
61
61
|
|
|
62
62
|
### `--webPort`
|
|
63
63
|
|
|
@@ -123,7 +123,7 @@ Vercel project and auth settings can often be inferred from `.vercel/project.jso
|
|
|
123
123
|
|
|
124
124
|
- Command: `workflow cancel`
|
|
125
125
|
- Default: unset
|
|
126
|
-
- Restricts the batch to this status. Only `pending` and `running` are accepted
|
|
126
|
+
- Restricts the batch to this status. Only `pending` and `running` are accepted; terminal runs cannot be canceled.
|
|
127
127
|
|
|
128
128
|
### `--workflowName` / `-n`
|
|
129
129
|
|
|
@@ -135,7 +135,7 @@ Vercel project and auth settings can often be inferred from `.vercel/project.jso
|
|
|
135
135
|
|
|
136
136
|
- Command: `workflow cancel`
|
|
137
137
|
- Default: `50`
|
|
138
|
-
- Maximum runs to cancel in one batch (1–500). Only one batch is
|
|
138
|
+
- Maximum runs to cancel in one batch (1–500). Only one batch is canceled per invocation; run the command again to cancel the next batch.
|
|
139
139
|
|
|
140
140
|
### `--confirm` / `-y`
|
|
141
141
|
|