---
title: Running Durable Agents on Vercel
description: Design durable AI agents on Vercel with patterns for execution recovery, human approval, safe retries, deployment changes, and persistent files.
url: "https://vercel.com/kb/guide/durable-ai-agents"
published: 2026-10-15
last_updated: 2026-10-15
authors: Anshuman Bhardwaj
install_vercel_plugin: npx plugins add vercel/vercel-plugin
---

Build durable agents on Vercel by combining the AI SDK agent loop with the Workflow SDK’s persisted execution. [Vercel Workflows](https://vercel.com/docs/workflows) runs the infrastructure. Step boundaries preserve intermediate results, approval hooks suspend execution, and idempotency keys help make external actions safe to retry.

These TypeScript examples are patterns for an existing application configured with the [Workflow SDK](https://workflow-sdk.dev/docs/getting-started). Install `@ai-sdk/workflow` with Workflow 5 and its `ai` and `zod` peer dependencies using the [WorkflowAgent setup](https://ai-sdk.dev/docs/agents/workflow-agent#installation).

## What are durable agents?

Durable agents record execution progress so they can reuse completed results and resume unfinished work after an interruption. Conversation history preserves model context; execution records establish which operations were completed and what should happen next.

[`WorkflowAgent`](https://ai-sdk.dev/docs/agents/workflow-agent) connects the AI SDK agent loop to the Workflow SDK’s durable execution. Recovery boundaries belong inside that loop, around model calls and external tool operations.

![Durable agent architecture](https://images.ctfassets.net/hjgychtc108g/6uqdDY3Ev3AzORKnLdFM6U/ea32fe042197d92ca680c6ed2100f485/durable-agents-light-4k.png)

How the agent loop, durable execution, application storage, and working files fit together.

## The architecture of a durable agent

Each component handles a different part of the agent’s execution or state.

| Component                 | Responsibility                                                  |
| ------------------------- | --------------------------------------------------------------- |
| `WorkflowAgent`           | Model calls and the agent’s tool loop                           |
| Workflow SDK              | Execution history, steps, retries, hooks, and timers            |
| Database                  | Application records and memory shared across runs               |
| Vercel Sandbox and Drives | An execution environment for tools and persistent working files |

The agent interprets the task and chooses tools. Steps perform external work; hooks and timers pause execution until an event arrives or a timer expires.

[Vercel Workflows](https://vercel.com/docs/workflows) stores workflow state and event history in managed persistence and uses Vercel Queues to dispatch execution. Once a run starts, the original request doesn’t need to remain open.

Choose storage according to what needs to survive: execution history for resuming a run, a database for application records and memory shared across runs, and persistent file storage for the workspace used by tools.

## Preserving progress through interruptions

Workflow SDK uses two directives to define [workflows and steps](https://workflow-sdk.dev/docs/foundations/workflows-and-steps):

- `'use workflow'` marks a function that coordinates execution.
  
- `'use step'` marks a function whose completed result is persisted for replay.
  

During recovery, the workflow runs its coordinating logic again and reuses recorded results from completed steps. Those completed operations don’t run again. Step functions have access to the Node.js runtime, so put HTTP requests, database calls, and SDK operations inside them.

Use `WorkflowAgent` for durable model calls and mark external tool functions with `'use step'`. This research agent reads only the two documentation URLs allowed inside `readDocument`; requests to other URLs or redirects fail.

```typescript
import { WorkflowAgent } from '@ai-sdk/workflow';
import { isStepCount, tool } from 'ai';
import { FatalError } from 'workflow';
import { z } from 'zod';

async function readDocument({ url }: { url: string }) {
  'use step';

  const allowedUrls = new Set([
    'https://workflow-sdk.dev/docs/foundations/workflows-and-steps',
    'https://ai-sdk.dev/docs/agents/workflow-agent',
  ]);

  if (!allowedUrls.has(url)) {
    throw new FatalError('Document URL is not allowed');
  }

  const response = await fetch(url, { redirect: 'error' });

  if (!response.ok) {
    throw new Error(`Document request failed: ${response.status}`);
  }

  return { url, text: await response.text() };
}

export async function research(
  prompt: string,
  modelId: string,
) {
  'use workflow';

  const agent = new WorkflowAgent({
    model: modelId,
    instructions:
      'Read the supplied documents and summarize their findings.',
    tools: {
      readDocument: tool({
        description: 'Read a document from an allowed URL.',
        inputSchema: z.object({ url: z.string().url() }),
        execute: readDocument,
      }),
    },
  });

  const result = await agent.generate({
    prompt,
    stopWhen: isStepCount(8),
  });

  return { text: result.text };
}
```

[`generate()`](https://ai-sdk.dev/docs/reference/ai-sdk-workflow/workflow-agent) runs the agent without streaming. The workflow returns only the final text, and `isStepCount(8)` limits the loop to eight model calls.

Place step boundaries around operations whose results are worth preserving independently. Wrapping an ordinary agent loop in one step records its result only after the loop finishes, so an interruption can require repeating the loop. Separate boundaries for model calls and external tools preserve intermediate progress.

Because inputs and outputs cross [serialization boundaries](https://workflow-sdk.dev/docs/foundations/serialization), pass data and identifiers between steps. Create database connections and SDK clients inside steps rather than trying to persist live handles.

## Waiting for human input

To wait for approval, await a [hook](https://workflow-sdk.dev/docs/api-reference/workflow/create-hook) that resumes the workflow when a reviewer submits a decision. Race it against a [durable timer](https://workflow-sdk.dev/docs/api-reference/workflow/sleep) to set a deadline. This example allows seven days for a response:

```typescript
import { createHook, sleep } from 'workflow';

export async function reviewProposal(proposalId: string) {
  'use workflow';

  using approval = createHook<{ approved: boolean }>({
    token: `proposal:${proposalId}:approval`,
  });

  const conflict = await approval.getConflict();
  if (conflict) {
    throw new Error(`Approval is already pending in run ${conflict.runId}`);
  }

  // Make the approval request available only after registration succeeds.
  return await Promise.race([
    approval.then(decision => ({
      kind: 'decision' as const,
      approved: decision.approved,
    })),
    sleep('7d').then(() => ({
      kind: 'expired' as const,
    })),
  ]);
}
```

The workflow calls `approval.getConflict()` before waiting for the decision. Proceed only when it returns `null`, which confirms that the hook is registered. Add any step that sends or exposes the approval request after that check so an immediate response can find the hook.

While suspended, the workflow doesn’t keep an application process running. It resumes when the decision arrives or the deadline expires.

Use the returned `kind` and `approved` values to continue with the action, reject it, or handle an expired request.

After authenticating the reviewer and checking their permission to approve the proposal, submit the decision from server-side code with [`resumeHook()`](https://workflow-sdk.dev/docs/api-reference/workflow-api/resume-hook):

```typescript
import { resumeHook } from 'workflow/api';

// After validating the decision and authorizing the reviewer:
await resumeHook(`proposal:${proposalId}:approval`, {
  approved: true,
});
```

## Making external actions safe to retry

An external operation can succeed before the process stops or loses its connection. If the step’s result hasn’t been recorded, Workflow SDK may retry the operation.

Use an idempotency key so the receiving service can treat repeated attempts as one action. This example requires an API that enforces the `Idempotency-Key` header:

```typescript
import { getStepMetadata } from 'workflow';

export async function submitAction(
  endpoint: string,
  payload: { proposalId: string; action: string },
) {
  'use step';

  const { stepId } = getStepMetadata();

  const response = await fetch(endpoint, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Idempotency-Key': `action:${stepId}`,
    },
    body: JSON.stringify(payload),
  });

  if (!response.ok) {
    throw new Error(`Action failed: ${response.status}`);
  }

  return response.json();
}
```

Workflow SDK’s [idempotency pattern](https://workflow-sdk.dev/docs/foundations/idempotency) uses a step ID that stays the same across retries of that invocation. Separate runs have different step IDs. To prevent duplicate actions across runs, use a business identifier or a database uniqueness constraint.

Check what happens if each tool runs twice. Reading a document is usually safe to repeat. Publishing content, charging a customer, or appending to a file requires a deduplication or recovery strategy.

## Keeping agents running as code changes

You can deploy updated code while agents are running or waiting for input. On Vercel, [deployment pinning](https://workflow-sdk.dev/docs/foundations/versioning) keeps each existing run on the deployment that started it, including its original step definitions. Runs started on the new deployment use the updated code.

Deploying a fix doesn't update an existing run. If a bug affects active work, cancel the affected runs and restart them on the corrected deployment. Before restarting, check how the new runs will handle previously completed external actions.

Keep database schemas and external APIs compatible with older code that may resume later. Deployment pinning preserves the workflow’s implementation, but its external dependencies can still change.

## Giving agents a persistent workspace

If your agent edits repositories, downloads documents, or generates artifacts, preserve its working files across sandbox sessions.

[Vercel Drives](https://vercel.com/docs/sandbox/concepts/drives) provide persistent directories for Vercel Sandbox. Files remain after a sandbox stops, and a later sandbox can mount the same drive.

Install `@vercel/sandbox` and configure [project authentication](https://vercel.com/docs/sandbox/sdk-reference#authentication).

```typescript
import { Drive, Sandbox } from '@vercel/sandbox';

export async function saveWorkspace(
  driveName: string,
  contents: string,
) {
  'use step';

  const drive = await Drive.getOrCreate({
    name: driveName,
    region: 'iad1',
  });

  const sandbox = await Sandbox.create({
    region: 'iad1',
    persistent: false,
    mounts: { '/workspace': drive },
  });

  try {
    await sandbox.writeFiles([
      {
        path: '/workspace/notes.md',
        content: Buffer.from(contents),
      },
    ]);

    return { driveName, path: '/workspace/notes.md' };
  } finally {
    await sandbox.stop();
  }
}
```

The example stores `notes.md` on the drive mounted at `/workspace`. The sandbox and drive use the same region, and `persistent: false` disables persistence for the sandbox’s own filesystem.

Only one sandbox can mount a drive for writing at a time. Multiple sandboxes can mount read-only snapshots concurrently. Each snapshot shows the files as they were when it was mounted; it doesn’t include later writes.

Keep live sandbox handles inside steps and pass identifiers between execution boundaries. The `finally` block stops the sandbox when the function exits. Abrupt process termination can skip that cleanup, so plan how retries will find and stop leftover sandboxes using the [Sandbox SDK](https://vercel.com/docs/sandbox/sdk-reference).

Overwriting a file with the same contents is easier to retry safely than appending data or running commands with other side effects.

## Next steps

Before deploying, verify the recovery behavior of each pattern you use:

- Interrupt a run between steps and confirm that recorded results are reused.
  
- Retry an external action and verify the service prevents duplicates.
  
- Submit an approval after suspension and confirm that the workflow resumes with the expected decision.
  
- Deploy new code and verify existing runs keep their original deployment.
  
- Stop a sandbox, mount its drive in another sandbox, and confirm that the saved files remain available.
  

To investigate recovery failures, open **Observability > Workflows** in your Vercel project and [inspect runs, step results, and errors](https://vercel.com/docs/workflows#observability).

For agents using Vercel Sandbox, use [Sandbox metrics](https://vercel.com/changelog/more-granular-observability-for-vercel-sandbox) to monitor sessions, CPU, memory, and data transfer.

### Read more

- [Build a web research agent with Workflow SDK](https://vercel.com/kb/guide/durable-web-research-agent-with-workflow-sdk)
  
- [Build AI agents with AI Gateway and AI SDK](https://vercel.com/kb/guide/ai-gateway-and-ai-sdk)
  
- [Build a daily digest bot with Chat SDK and Workflow SDK](https://vercel.com/kb/guide/daily-digest-bot-with-chat-sdk-and-workflow-sdk)
  
- [Create and mount Vercel Drives](https://vercel.com/kb/guide/vercel-drives)
  

## Frequently asked questions

### What is a durable AI agent?

Durable AI agents save execution progress outside their running processes. After an interruption, they can reuse completed results and retry unfinished work; they can also pause for external events. [`WorkflowAgent`](https://ai-sdk.dev/docs/agents/workflow-agent) uses the Workflow SDK to make the AI SDK agent loop durable.

### How do AI SDK and Workflow SDK work together?

`WorkflowAgent` connects AI SDK model calls and tools to Workflow SDK persistence, retries, hooks, and timers. Tool functions marked with `'use step'` execute as [durable steps](https://workflow-sdk.dev/docs/foundations/workflows-and-steps).

### Can a durable agent survive a server restart or redeployment?

Yes. Recorded progress lets a durable agent recover after a process interruption. On Vercel, [deployment pinning](https://workflow-sdk.dev/docs/foundations/versioning) keeps each existing run on its original deployment. Runs started on a new deployment use the updated code; redeploying leaves existing runs unchanged.

### How can an AI agent wait for human approval?

An agent's workflow can await a [hook](https://workflow-sdk.dev/docs/api-reference/workflow/create-hook), suspending execution until authenticated server-side code submits a decision through `resumeHook()`. Set an approval deadline with a durable timer. The application must authorize the reviewer and associate the decision with the specific proposal or action being approved.

### Does durable execution prevent duplicate tool actions?

No. Durable execution reuses recorded results from completed steps, but an interrupted attempt can still repeat an external action. Use an idempotency key enforced by the receiving service. Workflow SDK provides a [stable step ID](https://workflow-sdk.dev/docs/foundations/idempotency) across retries; preventing duplicates across separate runs requires a business identifier or database constraint.

### Do durable agents need Vercel Drives for persistent storage?

No. Agents that work entirely through APIs and databases may not need persistent files. Use [Vercel Drives](https://vercel.com/docs/sandbox/concepts/drives) when tools need to retain repositories, downloaded documents, or generated artifacts across sandbox sessions.

## More Vercel Workflows guides

- [Run recurring security reviews with deepsec on Vercel](/kb/guide/deepsec-reviews-on-vercel): Learn how to run periodic security scans on your code with deepsec. Set up deepsec to review GitHub repositories and deliver findings to GitHub and Slack using Vercel Connect, Workflows, Sandbox, and AI Gateway.
- [How to handle order-ahead traffic spikes on Vercel](/kb/guide/handle-order-ahead-traffic-spikes-on-vercel): Order-ahead traffic spikes hit the same routes every lunch hour. Learn how to scale, cache, queue, and test a restaurant ordering system on Vercel.
- [How to build a durable AI code agent on Vercel](/kb/guide/how-to-build-a-durable-ai-code-agent-on-vercel): Build an AI agent that generates code, writes its own tests, and executes them in an isolated microVM with automatic retries.