> ## Documentation Index
> Fetch the complete documentation index at: https://e2b.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Vercel Eve

> Run Vercel Eve agent sandboxes on E2B with the @e2b/eve-sandbox backend.

[Vercel Eve](https://vercel.com/docs/eve) is a filesystem-first framework for durable backend AI agents: you author an agent as files under `agent/`, and Eve compiles them into an app that runs on Vercel Functions. Every Eve agent has exactly one [sandbox](https://eve.dev/docs/sandbox) — the isolated bash environment rooted at `/workspace` that backs the built-in `bash`, `read_file`, `write_file`, `glob`, and `grep` tools.

The [`@e2b/eve-sandbox`](https://github.com/e2b-dev/eve-sandbox) package is an E2B backend for that sandbox — the E2B counterpart to Eve's built-in `vercel()`, `docker()`, `microsandbox()`, and `justbash()` backends. It implements the public `SandboxBackend` interface from `eve/sandbox`, so Eve itself needs no changes and no fork.

<Note>
  `@e2b/eve-sandbox` is experimental, and Eve is in beta. Both APIs may change.
</Note>

## Why E2B as the backend

|                | E2B backend                                                                           | Eve's local backends                                                         |
| -------------- | ------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Where it runs  | E2B cloud microVMs, from local dev and production alike                               | Docker daemon, local VM, or a simulated shell on the host                    |
| Startup        | \~150 ms from a snapshot or [custom template](/docs/template/quickstart)              | Image pull / VM boot on the developer machine                                |
| Environment    | Any [E2B template](/docs/template/quickstart) you build                               | Eve's `ghcr.io/vercel/eve` image, or a Docker image you supply               |
| Persistence    | [Auto-pause and resume](/docs/sandbox/persistence) — filesystem survives days of idle | Container/VM tied to the machine that started it                             |
| Egress control | E2B firewall: domain allow-lists and header injection                                 | Domain policies on `vercel()`/`microsandbox()`; `docker()` is all-or-nothing |

Use it when you want the same sandbox behavior in local dev, CI, and production, on infrastructure you control the image for.

## Prerequisites

* Node.js 22 or later
* An Eve project (`npx eve@latest init my-agent`)
* An [E2B API key](https://e2b.dev/dashboard?tab=keys)

## Install

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
npm i @e2b/eve-sandbox e2b
```

`eve` (>= 0.27) and `ai` (>= 7) are peer dependencies already present in an Eve project.

Set your key — the backend reads `E2B_API_KEY` unless you pass `apiKey`:

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
export E2B_API_KEY="e2b_***"
```

## Configure the backend

Author `defineSandbox` and pass `e2b()` as the backend:

```typescript title="agent/sandbox.ts" theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
import { defineSandbox } from 'eve/sandbox'
import { e2b } from '@e2b/eve-sandbox'

export default defineSandbox({
  backend: () => e2b({ template: 'base' }),
})
```

That is the whole integration. The agent's `bash` tool now runs commands in an E2B sandbox, its file tools read and write the sandbox filesystem, and nothing executes on your app runtime.

Prefer the **factory form** (`backend: () => e2b({...})`) over `backend: e2b({...})`: it defers reading environment variables until first use and memoizes the backend, so its prewarmed-snapshot cache survives across calls.

Use the folder layout (`agent/sandbox/sandbox.ts`) instead if you also seed files from `agent/sandbox/workspace/**`.

## Run the agent

```bash theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
pnpm dev        # or: npx eve dev
```

Ask the agent to run a command and it executes in a real E2B sandbox. Sandboxes created this way appear in your [E2B dashboard](https://e2b.dev/dashboard).

## Bootstrap and per-session setup

Eve has two lifecycle hooks, and the E2B backend maps each onto a different E2B primitive:

```typescript title="agent/sandbox/sandbox.ts" theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
import { defineSandbox } from 'eve/sandbox'
import { e2b } from '@e2b/eve-sandbox'

export default defineSandbox({
  backend: () =>
    e2b({
      template: 'base',
      timeoutMs: 30 * 60 * 1000,
      envs: { NODE_ENV: 'production' },
    }),

  // Build time, once per template — baked into a reusable E2B snapshot.
  async bootstrap({ use }) {
    const sandbox = await use()
    await sandbox.run({ command: 'sudo apt-get install -y jq' })
  },

  // Once per durable session — tighten egress for the turn.
  async onSession({ use }) {
    await use({ networkPolicy: { allow: ['*.npmjs.org', 'github.com'] } })
  },
})
```

* **`bootstrap`** runs during Eve's build-time `prewarm()`. The backend creates a sandbox, runs your bootstrap, writes your `workspace/` seed files, then captures an **E2B snapshot**. Later sessions fork that snapshot, so installs are paid once, not per session.
* **`onSession`** runs once per durable session against a live sandbox, and is the right place for network policy, per-user credentials, and one-time markers.

Snapshots are named from Eve's `templateKey` (which tracks your authored sandbox source, seed contents, and `revalidationKey`) plus a hash of the snapshot-affecting backend options — base template, baked `envs`, and network policy. Change any of those and the next build captures a fresh snapshot instead of reusing a stale one.

## Session persistence

E2B sandboxes are created with `lifecycle: { onTimeout: 'pause', autoResume: true }`, and the default timeout is **30 minutes** (E2B's own 5-minute default would expire mid-turn). On timeout the sandbox [pauses rather than dies](/docs/sandbox/persistence): the filesystem is preserved and the next message resumes it.

On the next turn the backend reattaches in this order:

1. The `sandboxId` persisted by Eve for that session.
2. A still-running or paused sandbox whose E2B metadata matches `eveBackend: "e2b"` and the session's `eveSessionKey`.
3. Otherwise a fresh sandbox, forked from the prewarmed snapshot.

Two consequences worth knowing:

* **The backend's `shutdown()` is intentionally a no-op.** Killing the sandbox on server shutdown would drop background work and force Eve to recreate it without rerunning `onSession`. Sandboxes are left paused and expire on their own — kill them from the [dashboard](https://e2b.dev/dashboard) or the [SDK](/docs/sandbox) if you want them gone sooner. Opt out with `autoPause: false` to kill on timeout instead.
* **Reconnects do not re-apply the configured `networkPolicy`.** A resumed sandbox keeps its live policy, including any tightening `onSession` applied. Re-stamping the create-time default could silently loosen a locked-down session.

## Network policy

Egress rules go on the factory (applied to each fresh session, before authored `bootstrap` runs) or in `onSession`'s `use()`. The backend translates Eve's `SandboxNetworkPolicy` into an [E2B firewall](/docs/network/internet-access) update:

| Eve policy                                            | E2B update                                   |
| ----------------------------------------------------- | -------------------------------------------- |
| `"allow-all"` (default)                               | `allowInternetAccess: true`                  |
| `"deny-all"`                                          | `allowInternetAccess: false`                 |
| `{ allow: ['github.com', '*.npmjs.org'] }`            | `allowOut: [...]` + `denyOut: ['0.0.0.0/0']` |
| `{ allow: ['*'], subnets: { deny: ['10.0.0.0/8'] } }` | `denyOut: ['10.0.0.0/8']`                    |
| `{ allow: [] }`                                       | `allowInternetAccess: false`                 |

Restricting egress to an allow-list requires the catch-all in `denyOut` — E2B gives allow rules absolute precedence over deny rules, so the listed hosts pass and everything else is blocked. The backend adds that for you.

<Warning>
  Because allow beats deny in E2B, some Eve policies cannot be expressed faithfully. The backend **throws instead of silently weakening them**:

  * `subnets.deny` combined with an allow-list — the "denied" hosts would stay reachable. Use `{ allow: ['*'], subnets: { deny: [...] } }` for deny-lists, or drop `subnets.deny` (anything outside an allow-list is already blocked).
  * A per-rule `match` condition — E2B applies header transforms to every request to a host.
  * `forwardURL` request proxying — no E2B equivalent.
  * A header `transform` alongside a catch-all `"*"` allow — a transform host must be allow-listed, which an allow-all cannot also be.
</Warning>

### Credential brokering

E2B can inject a header at the firewall so a secret authenticates egress without ever entering the sandbox. Eve expresses this as a per-domain `transform`:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
async onSession({ use }) {
  await use({
    networkPolicy: {
      allow: {
        'github.com': [{ transform: [{ headers: { authorization: 'Basic your_base64_credentials_here' } }] }],
        'api.example.com': [],
      },
    },
  })
}
```

List every host explicitly. Eve's documented `"*": []` catch-all pattern is rejected by this backend for the reason above — pair transforms with an explicit allow-list instead.

To change policy mid-turn, call `sandbox.setNetworkPolicy(...)` on the live handle from any authored tool.

## Custom templates

`template` accepts any E2B template ID or alias. Build a [custom template](/docs/template/quickstart) with your runtimes, system packages, and toolchain pre-installed, and every session starts from it:

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
export default defineSandbox({
  backend: () => e2b({ template: 'your-template-id-or-name' }),
})
```

Templates and snapshots compose: the template is the base image, and Eve's `bootstrap` layers your agent-specific setup into a snapshot on top of it. Put slow, stable work (compilers, system packages) in the template; put agent-specific work (cloning a baseline repo, installing project dependencies) in `bootstrap`.

## Backend options

```typescript theme={"theme":{"light":"github-light","dark":"github-dark-default"}}
e2b({
  template: 'base',                  // E2B template ID or alias
  timeoutMs: 30 * 60 * 1000,         // auto-pause timeout; default 30 minutes
  envs: { NODE_ENV: 'production' },  // env vars baked into every sandbox
  metadata: { team: 'growth' },      // E2B metadata, create-time only
  tags: { tier: 'beta' },            // diagnostic tags, merged into metadata
  apiKey: process.env.E2B_API_KEY,   // defaults to E2B_API_KEY
  domain: 'e2b.dev',                 // self-hosted or region endpoint
  networkPolicy: 'allow-all',        // initial policy for each fresh session
  autoPause: true,                   // false → kill on timeout instead of pause
  createOptions: {},                 // raw E2B SandboxOpts escape hatch
})
```

`createOptions` is merged into every `Sandbox.create()` call, so anything the [E2B JavaScript SDK](/docs/sdk-reference/js-sdk) supports is reachable even when this backend has no dedicated option for it. Explicit options win over `createOptions`.

## How the integration works

| Component       | Responsibility                                                                     |
| --------------- | ---------------------------------------------------------------------------------- |
| Eve runtime     | Runs turns, owns durable session state, calls the backend's `prewarm` and `create` |
| `defineSandbox` | Declares the backend plus the `bootstrap` and `onSession` hooks                    |
| `e2b()` backend | Creates, reconnects, and configures E2B sandboxes; maps network policy             |
| E2B snapshot    | Captures bootstrap + seed files once, forked per session                           |
| E2B template    | Base OS, runtimes, and pre-installed dependencies                                  |

Paths line up because the backend anchors relative paths to `/workspace`, Eve's cross-backend namespace — E2B's own default working directory is `/home/user`, and the backend creates `/workspace` during base setup. Every E2B API call this backend makes is tagged with an `eve-sandbox/<version>` integration identifier.

## Learn more

* [`@e2b/eve-sandbox` on GitHub](https://github.com/e2b-dev/eve-sandbox) — source, unit tests, and a runnable Next.js example
* [Eve sandbox documentation](https://eve.dev/docs/sandbox) — session handle API, lifecycle hooks, and backends
* [Eve on Vercel](https://vercel.com/docs/eve) — how Eve maps onto Vercel Functions, Workflows, and AI Gateway

## Related guides

<CardGroup cols={3}>
  <Card title="Templates" icon="layer-group" href="/docs/template/quickstart">
    Build custom sandbox templates with pre-installed dependencies
  </Card>

  <Card title="Sandbox persistence" icon="clock" href="/docs/sandbox/persistence">
    Auto-pause, resume, and manage sandbox lifecycle
  </Card>

  <Card title="Internet access" icon="shield" href="/docs/network/internet-access">
    Restrict sandbox egress with domain allow-lists
  </Card>
</CardGroup>
