Refund flows get built as workflows and run cleanly for months. Then finance asks for one more approval step, and the change takes a sprint because the process lives in application code only backend engineers can touch.

Nothing about the engine was wrong. It was picked on retries, timers, and observability, which nearly every engine offers, rather than on who would edit the workflow later.

This guide covers what an engine does at runtime, how the four types differ by who authors the workflow, and the criteria that decide most evaluations.

**Key takeaways:**

- A workflow engine packages a state machine, a scheduler, and durable persistence into one runtime, so a defined workflow executes to completion across crashes and restarts.

- Engines split into four types by authoring model: BPM-heritage, code-first, DAG/data, and serverless-native.

- Versioning in-flight runs is the mechanic teams discover late, because a deploy mid-run can execute a workflow against code that no longer matches its history.

- Durability guarantees, language support, the local development story, and the hosting model decide most evaluations.

- Serverless-native engines compile orchestration into the application, so [Vercel Workflows](https://vercel.com/docs/workflows) runs durable execution with no cluster to operate.

## [Copy link to heading](#what-is-a-workflow-engine)What is a workflow engine?

A workflow engine is the software that executes and manages defined workflows, packaging a state machine, a scheduler, and durable persistence into a single runtime. The state machine tracks which step a run has reached, and the scheduler decides when the next one fires. Persistence records the result of each step, so a crash takes down the process without taking down the run.

Assembling those three pieces by hand is the alternative, and most teams have done it: a status column for state, cron or a queue for scheduling, and a database table for persistence. An engine's claim is that the three belong in one runtime, because keeping them consistent across three systems is the work that never finishes. Packaging them that way turns [workflow orchestration](https://vercel.com/i/workflow-orchestration) from a pattern you implement into software you install.

## [Copy link to heading](#what-a-durable-workflow-engine-does-at-runtime)What a durable workflow engine does at runtime

Five mechanics distinguish an engine from a scheduler with retry logic bolted on.

### [Copy link to heading](#step-execution-and-state-persistence)Step execution and state persistence

A step is the unit the engine records. It writes inputs and outputs around each one to durable storage, so recovery replays the recorded history and resumes at the boundary after the last step that finished rather than at the top.

Most engines record this as an append-only event log. On Vercel, [every state transition](https://workflow-sdk.dev/docs/how-it-works/event-sourcing) persists as an event, with a normal step producing `step_created`, `step_started`, and `step_completed`, plus a `step_retrying` event for each transient failure. Event granularity determines what the engine can show you later and what it charges for.

### [Copy link to heading](#timers,-sleeps,-and-external-waits)Timers, sleeps, and external waits

An engine treats time as a first-class primitive rather than a `setTimeout` the process has to stay alive for. A run can sleep for minutes or months, and a [sleeping run](https://vercel.com/docs/workflows/concepts) accrues no compute cost because no instance stays alive during the wait.

External waits work the same way. A run pauses at a step that needs a human approval, a webhook, or a payment confirmation, then resumes when the signal arrives. Engines that lack this primitive push teams into polling loops and a hand-rolled state table, rebuilding the thing the engine was meant to replace.

### [Copy link to heading](#retry-policy-attached-to-the-step)Retry policy attached to the step

Retry configuration belongs to the step, not the run, because the two failure classes need different treatment. A rate-limited model call wants a long provider-specified delay, whereas a connection reset wants a short one.

Vercel Workflows handles [errors and retries](https://workflow-sdk.dev/docs/foundations/errors-and-retries) at the step level, retrying each step up to 3 times by default, for a total of 4 attempts, with `maxRetries` configurable per step. Error types cover the rest, with `FatalError` skipping retries for failures that won't recover and `RetryableError` setting an explicit delay.

### [Copy link to heading](#versioning-in-flight-runs)Versioning in-flight runs

Workflow versioning often becomes important only after the first deployment interrupts an in-flight run. Imagine a run started an hour ago that's still executing when you deploy a fix. If the engine hands that run to the new code, replay meets a history the code no longer matches.

Engines address this by pinning. On Vercel, runs are [tied to a deployment](https://workflow-sdk.dev/docs/foundations/versioning), so existing runs continue on the deployment that started them and later code changes don't reach them. A `deploymentId` of `latest` opts a new run into the current deployment instead.

[Temporal's Worker Versioning](https://docs.temporal.io/production-deployment/worker-deployments/worker-versioning) makes the same guarantee through a behavior declared per workflow type, either pinned to the version it started on or auto-upgraded as you roll out. An engine without a version story leaves you writing branching code paths inside the workflow to keep old runs alive.

### [Copy link to heading](#visibility-and-audit)Visibility and audit

The event log doubles as the audit trail. When a run fails, the question is which step, on which input, after how many attempts, and an engine that persists every transition resolves it without a custom status table or log grepping.

For regulated and financial work, the record of what executed is itself a deliverable, so the audit trail carries weight beyond debugging. Engines differ widely in whether that history is queryable, how long it's retained, and whether inspecting it requires their own interface.

## [Copy link to heading](#four-types-of-workflow-engine-compared)Four types of workflow engine compared

Engines cluster by who authors the workflow and in what language. The authoring model constrains the local development story, the hiring profile, and everything else downstream:

| Type | Authoring model | Representative | Strongest fit |
| --- | --- | --- | --- |
| BPM-heritage | Visual BPMN diagrams, business analysts alongside engineers | [Camunda](https://camunda.com/platform/) | Approval chains and process automation with non-engineer stakeholders |
| Code-first | Workflow definitions in general-purpose code | Temporal, Inngest | Engineering-owned backend processes with complex branching |
| DAG/data | Task graphs on a schedule, data-team owned | [Apache Airflow](https://airflow.apache.org/docs/apache-airflow/stable/core-concepts/dags.html) | Scheduled ETL and analytics pipelines |
| Serverless-native | Directives inside existing application code | Vercel Workflows | Application backends and AI agents already deployed serverless |

A BPM engine at a company where operations staff maintain the process beats a code-first engine only three engineers can change. An Airflow DAG for a nightly warehouse load beats a durable execution runtime. Adopting the wrong type shows up as workflows nobody outside one team can modify.

## [Copy link to heading](#serverless-native-engines-and-vercel-workflows)Serverless-native engines and Vercel Workflows

Serverless-native is the newest of the four types, and it inverts the usual arrangement. Instead of running an engine beside the application, the engine compiles into it.

### [Copy link to heading](#orchestration-compiled-into-application-code)Orchestration compiled into application code

Standing up an engine has usually meant standing up a distributed system first. A database, a search cluster, several service components, and a worker fleet all need all need to be deployed, scaled, and monitored on top of the application they coordinate. That's a large amount of infrastructure to own for retries and resumability.

Vercel Workflows removes the orchestrator. Coordination runs in the application's own functions, built on three pieces the platform already provides. An event log holds execution state, [Vercel Functions](https://vercel.com/docs/functions) on [Fluid compute](https://vercel.com/docs/fluid-compute) run each step, and [Vercel Queues](https://vercel.com/docs/queues) enqueue the next one.

Two directives turn ordinary async code into a durable workflow:

```
export async function processVideo(assetId: string) {
  'use workflow';

  const transcript = await generateTranscript(assetId);
  const moderation = await runModeration(transcript);

  return publish(assetId, moderation);
}

async function generateTranscript(assetId: string) {
  'use step';

  return fetchTranscript(assetId);
}
```

The workflow function is sandboxed for determinism and can't reach the network or the file system, whereas step functions handle the side effects. Each `'use step'` function compiles to its own isolated invocation with its own retry policy.

### [Copy link to heading](#waits-that-don't-hold-compute)Waits that don't hold compute

The cost of a long wait has little to do with the engine and everything to do with the billing model underneath it. Under wall-clock billing, a function waiting for a model response or human approval is charged for the time it remains open, which can push teams toward shorter timeouts and fragmented logic.

Fluid compute separates the two things a waiting function costs. Active central processing unit (CPU) time is billed only while the function is computing, and it stops the moment the function blocks on input/output (I/O). The cheaper memory rate is the only charge that continues during the wait. Vercel's own [AI Gateway](/blog/how-ai-gateway-runs-on-fluid-compute) shows how wide that gap runs, handling roughly 16,000 runtime hours in its first month of general availability, whereas only about 1,200 of those hours involved CPU work.

### [Copy link to heading](#version-safety-without-a-deployment-strategy)Version safety without a deployment strategy

Version pinning only works if the old code is still running somewhere. A self-managed engine puts that on you. You need a deployment strategy that keeps retired versions alive until every in-flight run pinned to them has finished, plus the routing to send those runs to the right workers. Getting it wrong corrupts runs quietly.

On Vercel, immutable deployments handle both. Each run finishes on the deployment that created it; new runs pick up the latest deploy; and step inputs, outputs, and stream chunks are [encrypted before they leave](/blog/a-new-programming-model-for-durable-execution) the deployment. Between the October 2025 beta and general availability on April 16, 2026, the model handled over 100 million runs and over 500 million steps across more than 1,500 teams.

## [Copy link to heading](#how-to-evaluate-a-durable-workflow-engine)How to evaluate a durable workflow engine

Type narrows the field, and four criteria decide within it. Each is cheap to check up front and expensive to discover after a migration has started.

Work through them before committing to a proof of concept:

- **Durability guarantees:** Determine whether the engine recovers by deterministic replay or by restoring checkpoints. Replay re-executes the workflow from the top and skips finished steps using recorded history, which demands strictly deterministic code and returns a uniform guarantee. Checkpointing constrains code less and lets anything outside a checkpoint re-run with different values, which is fine for idempotent pipelines and expensive for payments.

- **Language support:** Confirm the engine runs the language the workflow logic already lives in. Some engines are TypeScript-only, and the Workflow SDK adds Python. A service in an unsupported language has to be rewritten or called over HTTP from a step, which puts the durability boundary outside the code doing the work.

- **Local development story:** Test whether a workflow runs on a laptop without provisioning infrastructure first. The Workflow SDK's Local World supplies [virtual infrastructure](/blog/introducing-workflow) so workflows execute with no queue or database behind them, and the same code behaves identically once deployed. Engines that need a live cluster to exercise anything push every test into a shared environment, which slows each iteration for the life of the project.

- **Hosting model:** Price the operational surface before comparing features, because that bill outlasts the evaluation. Self-hosting an engine like Temporal means a PostgreSQL or Cassandra backend, an Elasticsearch cluster, and four service components deployed separately, typically via Helm on Kubernetes. Managed and serverless-native options trade that surface for a vendor relationship, which is worth pricing against the engineering time it replaces.

Workflow SDK is [open source](/blog/a-new-programming-model-for-durable-execution) with an adapter system that supplies the three components a workflow needs against different infrastructure: an event log, compute, and a queue. A managed run and a self-hosted run share the same application code, so a hosting decision stays reversible.

## [Copy link to heading](#when-cron-and-a-queue-beat-a-workflow-engine)When cron and a queue beat a workflow engine

An engine earns its place when a run accumulates state worth keeping. If a failed attempt can start over from the beginning at acceptable cost, cron and a queue already cover the job.

Scheduled work that tolerates an occasional miss needs a trigger rather than a runtime. Single-step background work that's cheap to repeat needs at-least-once delivery rather than replay. Neither carries progress between steps, because neither has steps, so durability has nothing to protect.

Two things push work across that line. Expensive completed steps turn a full restart into a second invoice, and a run that has to pause for hours leaves no process alive to hold its progress. In both cases the queue is left holding a message that records delivery and nothing about how far the work got. Reaching for an engine before either shows up buys durability for work with nothing to lose.

## [Copy link to heading](#match-the-engine-to-how-your-team-writes-workflows)Match the engine to how your team writes workflows

The engine that fits is rarely the one with the longest feature list. Three constraints do most of the work: the authoring model has to match who maintains the workflow, the language has to match the code around it, and the hosting model has to match the operational budget you have. Together they eliminate most of the field before durability semantics come up, which is why a decision that starts from a feature comparison tends to get relitigated a year later.

Here's what Vercel provides for teams running durable multi-step work:

- **Vercel Workflows:** Durable execution through `'use workflow'` and `'use step'` directives in application code, with per-step retries and no limit on run duration.

- **Fluid compute:** Active CPU billing pauses while a function waits on model responses or other I/O, so long waits accrue only the lower memory rate.

- **Vercel Queues:** At-least-once delivery on a durable append-only log, with idempotency-key deduplication for the full retention period of a message, up to 7 days.

- **Deployment-pinned runs:** Each run finishes on the deployment that created it, so a mid-run deploy can't hand a run to code its history doesn't match.

- **Portable runtime:** Workflow SDK is open source, and its adapter system runs the same workflow code against self-hosted infrastructure.

[Start a new project](https://vercel.com/new) to run durable workflows inside your application, or browse [workflow templates](https://vercel.com/templates) for examples already wired up.

## [Copy link to heading](#frequently-asked-questions-about-workflow-engines)Frequently asked questions about workflow engines

### [Copy link to heading](#what-is-the-difference-between-a-workflow-engine-and-an-orchestrator)What is the difference between a workflow engine and an orchestrator?

Orchestration is the practice of coordinating a multi-step process from one place, and an engine is that practice packaged as software. Any component that sequences the calls and holds execution state is the orchestrator, hand-built or installed. The [patterns behind orchestration](https://vercel.com/i/workflow-orchestration) apply either way.

### [Copy link to heading](#how-is-a-workflow-engine-different-from-a-job-scheduler)How is a workflow engine different from a job scheduler?

A scheduler decides when work starts and stops caring after the trigger fires. An engine owns the run from start to completion, tracking which step finished and resuming after a crash. Schedulers determine when work starts, and engines track what happens after.

### [Copy link to heading](#is-a-workflow-engine-the-same-as-a-state-machine)Is a workflow engine the same as a state machine?

A state machine is one component inside an engine, alongside the scheduler and the persistence layer. Code-first and serverless-native engines infer the machine from ordinary control flow, so there's no separate state chart to define, whereas BPM engines expose it as the authoring surface.

### [Copy link to heading](#do-you-need-a-workflow-engine-for-a-single-background-job)Do you need a workflow engine for a single background job?

No. One-step work that's cheap to repeat is well served by a queue with at-least-once delivery. An engine starts paying off once a run has multiple expensive steps, or has to survive longer than a function timeout while waiting on something external.