UNPKG

workflow

Version:

Workflow SDK - Build durable, resilient, and observable workflows

105 lines (81 loc) • 8.35 kB
--- title: Workflow SDK vs trigger.dev 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. type: conceptual 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. prerequisites: - /docs/foundations/workflows-and-steps related: - /docs/foundations/errors-and-retries - /docs/foundations/streaming - /docs/ai --- [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. <Callout type="info"> **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. </Callout> ## At a glance | | Workflow SDK | trigger.dev | | --- | --- | --- | | **Category** | Open-source durable-functions SDK that runs in your app | Durable task platform with its own runtime (Cloud or self-hosted) | | **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 | | **Authoring** | `"use workflow"` / `"use step"` in your existing app | `task()` / `schemaTask()` deployed to trigger.dev as a separate target (Docker image) | | **Languages** | TypeScript / JavaScript (Python beta) | **TypeScript / JavaScript only** | | **Where it runs** | Co-located with your app (Vercel managed or self-host) | trigger.dev's run engine (isolated containers) | | **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) | | **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` | | **Concurrency control** | Enforce in steps / at the publisher | First-class queues + concurrency keys | | **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 | | **Pricing** | SDK free; pay your platform | Cloud: compute-seconds + per-run ($0.0000338/s Small + $0.000025/run); no charge while checkpointed | | **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 | **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. ## The core difference: checkpoint/restore vs. replay 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. 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. 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. ## AI agents 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. ## Migrating from trigger.dev | trigger.dev | Workflow SDK | Note | | --- | --- | --- | | `task({ id, run })` | `"use workflow"` function started with `start()` | No factory or id registry. | | `schemaTask({ schema, run })` | Typed function + `"use workflow"` | Validate inputs at the call site. | | Inline `run` body | `"use step"` functions | Side effects move into named steps. | | `wait.for` / `wait.until` | `sleep('5m')` / `sleep(date)` | Import from `workflow`. | | `wait.forToken({ timeout })` | `createHook()` + `Promise.race` with `sleep()` | Hooks carry a typed token. | | `triggerAndWait()` | [`start()`](/docs/foundations/starting-workflows) called directly from the workflow, then await the returned `Run` | Spawn + collect. | | `batch.triggerAndWait()` | `Promise.all` over collected `Run` handles | Standard concurrency. | | `metadata.stream()` / Realtime | `getWritable()` / named streams | Clients read from the stream. | | 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). | | `AbortTaskRunError` | `FatalError` | Stops retries immediately. | The `task()` factory collapses into a plain function, and because the workflow body is replayed, move side effects into steps: ```typescript title="workflows/order.ts" export async function processOrder(orderId: string) { 'use workflow'; // [!code highlight] const order = await loadOrder(orderId); return { orderId: order.id, status: 'completed' }; } async function loadOrder(orderId: string) { 'use step'; // [!code highlight] const res = await fetch(`https://example.com/api/orders/${orderId}`); return res.json() as Promise<{ id: string }>; } ``` <Callout type="warn"> 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. </Callout> <Callout type="info"> Install the migration skill to translate a trigger.dev app automatically: ```bash npx skills add https://github.com/vercel/workflow --skill migrating-to-workflow-sdk ``` </Callout> ### trigger.dev features without a direct Workflow SDK equivalent Each row is a trigger.dev capability the Workflow SDK does not replicate one-to-one, paired with how to cover it on the Workflow SDK side: | trigger.dev feature | How to cover it with the Workflow SDK | | --- | --- | | Concurrency keys / queue concurrency limits | Enforce limits inside steps or debounce at the publisher | | `schedules.task()` / cron | Trigger from Vercel Cron or a system cron calling `start()` | | `machine` presets / custom images | Function resources are per-deployment (configured via your hosting platform) | --- *Compiled from public documentation. Verify current trigger.dev limits and pricing against [trigger.dev/docs](https://trigger.dev/docs). Not based on head-to-head benchmarks.*