Sandboxes

Providers

A provider owns the isolation primitive: where the harness actually runs. Every provider implements the same SandboxProvider / SandboxHandle contract, so the workspace you hand the agent and the policy that guards it are provider-agnostic. Pick a provider for the isolation, auth, and snapshot/resume behaviour you need; the rest of your sandbox definition stays the same.

The provider is where the agent runs. For which agent runs — Grok Build, Claude Code, Codex, OpenCode, or any ACP agent via acpCompatible — see Harnesses.

Choosing a provider

ProviderPackageIsolationNotes
Local process@tanstack/ai-sandbox-local-processnone (host)The fast, no-Docker dev loop. Trusted/dev use only.
Docker@tanstack/ai-sandbox-dockercontainerReal isolation; commit-based snapshots, fork, resume-by-id.
Daytona@tanstack/ai-sandbox-daytonacloud sandboxManaged Daytona sandboxes; port preview links, resume-by-id. Needs DAYTONA_API_KEY.
Vercel@tanstack/ai-sandbox-vercelmicroVMManaged Vercel Sandbox microVMs; exposed-port domains, resume-by-id (persistent). Needs VERCEL_TOKEN + team/project.

Each provider is its own package, and the constructor is the only thing that differs between them:

ts
import { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'
import { dockerSandbox } from '@tanstack/ai-sandbox-docker'
import { daytonaSandbox } from '@tanstack/ai-sandbox-daytona'
import { vercelSandbox } from '@tanstack/ai-sandbox-vercel'

const dev = localProcessSandbox() // runs on your host
const isolated = dockerSandbox({ image: 'node:22' }) // runs in a container
const daytona = daytonaSandbox({ apiKey: process.env.DAYTONA_API_KEY }) // managed cloud sandbox
const vercel = vercelSandbox({ runtime: 'node24' }) // managed Vercel microVM

Cloud providers (Daytona, Vercel) run as remote VMs. When you drive them from your laptop, tools bridged from chat() can't dial your machine's localhost — you need the bridge tunnel. See the tools guide for the ngrok subpath, and the Cloudflare guide for the edge-native co-located model.

Local process

ts
import { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'

const dev = localProcessSandbox()
  • Isolation: none. The harness runs directly on your host, inheriting your host environment. Use it for trusted/dev work only — there is no boundary between the agent and your machine.

  • Auth / env: inherits the host environment. No API key injection is required if your host CLI is already logged in.

  • Snapshot / resume: no snapshots and no durable resume-by-id; each run re-creates and re-bootstraps under the same identity. The snapshot step is skipped silently (see Capabilities).

Use a host CLI's own auth (scrubEnv)

Because localProcessSandbox runs the harness on your host, it inherits your host environment — including any API keys exported there. Use scrubEnv to remove variables before spawning, so the host CLI falls back to its own logged-in session instead of billing the API. For example, drop XAI_API_KEY so Grok Build uses your grok.com login (the same trick works for Claude Code with ANTHROPIC_API_KEYclaude login):

ts
import { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'

const hostLogin = localProcessSandbox({ scrubEnv: ['XAI_API_KEY'] })

Only local-process can do this — it is the only provider that runs your host CLI. Isolated and cloud providers have no host login, so they always use an injected API key (supplied as a workspace secret).

Docker

ts
import { dockerSandbox } from '@tanstack/ai-sandbox-docker'

const isolated = dockerSandbox({ image: 'node:22' })
  • Isolation: a real container boundary between the agent and your host.

  • Auth / env: no host login; provide credentials as workspace secrets, which are injected into the container env at create/resume. The agent reaches host tools over host.docker.internal (see tools).

  • Snapshot / resume: full commit-based snapshots, fork, and resume-by-id. Bootstrap snapshots after setup completes, so subsequent runs resume from the snapshot instead of re-running setup.

Daytona

ts
import { daytonaSandbox } from '@tanstack/ai-sandbox-daytona'

const daytona = daytonaSandbox({ apiKey: process.env.DAYTONA_API_KEY })
  • Isolation: a managed cloud sandbox — a remote VM you don't run yourself.

  • Auth / env: needs DAYTONA_API_KEY. Harness credentials are injected as workspace secrets; there is no host login to fall back on.

  • Snapshot / resume: no snapshots; resume-by-id reconnects to a still-running sandbox (not a restored point-in-time snapshot), plus port preview links for live previews.

  • Bridge: the sandbox is remote, so a bridged tool call can't reach your laptop's localhost. In local dev, tunnel the bridge (see tools); a deployed orchestrator is reachable out of the box.

Vercel

ts
import { vercelSandbox } from '@tanstack/ai-sandbox-vercel'

const vercel = vercelSandbox({ runtime: 'node24' })
  • Isolation: a managed microVM (Vercel Sandbox).

  • Auth / env: needs VERCEL_TOKEN plus a team/project. Harness credentials are injected as workspace secrets.

  • Snapshot / resume: persistent resume-by-id with a durable filesystem, plus exposed-port domains for previews.

  • Bridge: like Daytona, a remote VM — bridged tools need the tunnel in local dev (see tools).

Capabilities

Providers declare what they support via capabilities(). The flags are:

CapabilityMeaning
fsRead/write the sandbox filesystem.
execRun commands.
envInject environment variables.
portsExpose/forward ports (preview URLs).
backgroundProcessesKeep long-running processes alive between calls.
writableStdinA spawned process exposes a writable host→process stdin. true for local-process and Docker; false on remote/edge providers (Daytona, Vercel, Cloudflare), where stdin-fed harnesses deliver the prompt via a file + shell redirection instead.
snapshotsCapture and restore point-in-time snapshots.
networkPolicyEnforce network allow/deny rules.
durableFilesystemDisk that survives across resumes.
forkBranch a sandbox from an existing one.

Code that uses an optional capability checks the flag first and degrades gracefully — for example, bootstrap only snapshots when snapshots is supported, so localProcessSandbox simply skips the step. Calling an unsupported optional method directly (instead of checking the flag) throws an UnsupportedCapabilityError:

ts
import { localProcessSandbox } from '@tanstack/ai-sandbox-local-process'

const provider = localProcessSandbox()
const caps = provider.capabilities()

if (caps.snapshots) {
  // safe to take a snapshot
} else {
  // degrade gracefully — local-process has no snapshots
}

Use the flags to write provider-agnostic code: branch on the capability rather than the concrete provider, and your sandbox definition keeps working when you swap one provider for another.