sandbox
Creates isolated Linux MicroVMs using Vercel Sandbox SDK. Use when building code execution environments, running untrusted code, spinning up dev servers, testing in isolation, or when the user mentions "sandbox", "microvm", "isolated execution", or "@vercel/sandbox".
ソース情報
- リポジトリ
- vercel/sandbox
- ソースの最終更新活動
- 2026年10月16日 21:27
- 検出された SKILL.md の言語
- 英語
- スター
- 212
- フォーク
- 45
インストール方法
デフォルトでは、最初にソースを確認する Prompt が選択されています。直接コマンドに切り替えるか、ローカルコピーをダウンロードすることもできます。
ソースファイルを確認
インストールを決める前に、SKILL.md と SkillsMP に表示されている付属ファイルをお読みください。
SKILL.md を表示中
SKILL.md
ソースの指示 · 読み取り専用プレビュー- name
- sandbox
- description
- Creates isolated Linux MicroVMs using Vercel Sandbox SDK. Use when building code execution environments, running untrusted code, spinning up dev servers, testing in isolation, or when the user mentions "sandbox", "microvm", "isolated execution", or "@vercel/sandbox".
- metadata
- {"author":"Vercel Inc.","version":"2.0"}
## _CRITICAL_: Always Use Correct `@vercel/sandbox` Documentation
Your knowledge of `@vercel/sandbox` may be outdated.
Follow these instructions before starting on any sandbox-related tasks:
### Official Resources
- **Documentation**: https://vercel.com/docs/vercel-sandbox
- **SDK Reference**: https://vercel.com/docs/vercel-sandbox/sdk-reference
- **CLI Reference**: https://vercel.com/docs/vercel-sandbox/cli-reference
- **GitHub**: https://github.com/vercel/sandbox
- **REST API**: https://vercel.com/docs/rest-api/sandboxes
### What changed in v2
The `@vercel/sandbox@2` SDK and `sandbox@3` CLI replace anonymous, ephemeral
sandboxes with **named, persistent** sandboxes. Key differences from v1:
- Sandboxes are identified by **`name`** (not `sandboxId`). Names are unique per project.
- Sandboxes are **persistent by default** — when a sandbox stops, the SDK
automatically snapshots it and restores the filesystem on the next resume.
- A **Session** is a single running VM instance inside a sandbox. SDK calls
like `runCommand`, `writeFiles`, etc. automatically resume a stopped sandbox.
- New methods: `Sandbox.getOrCreate`, `Sandbox.fork`, `sandbox.update`,
`sandbox.delete`, `sandbox.listSessions`, `sandbox.listSnapshots`,
`Snapshot.tree`, `defineSandboxProxy`.
- New params: `name`, `persistent`, `tags`, `onResume`, `snapshotExpiration`,
`keepLastSnapshots`, L7 network policy matchers, `forwardURL`.
- Pagination uses **cursor-based** iterators (async-iterable) instead of `since`/`until`.
- `Sandbox.list({ since, until })` → `Sandbox.list({ cursor, namePrefix, sortBy, tags })`.
- v1 sandboxes are backfilled so the only required code change is using `name`
instead of `sandboxId`.
### Quick Reference
**Essential imports:**
```typescript
// Core SDK
import {
Sandbox,
Session,
Snapshot,
Drive,
Command,
CommandFinished,
} from "@vercel/sandbox";
import { APIError, StreamError } from "@vercel/sandbox";
// For advanced network policy with credential brokering and L7 matchers
import type {
NetworkPolicy,
NetworkPolicyRule,
NetworkTransformer,
} from "@vercel/sandbox";
// For implementing a request-forwarding proxy (forwardURL)
import { defineSandboxProxy } from "@vercel/sandbox/proxy";
// For timeouts
import ms from "ms"; // e.g., ms("5m"), ms("1h")
```
**Default image:** Sandboxes use `vercel/sandbox/universal:latest`, an
Ubuntu-based image with Node.js 24, Bun, Python 3.14, coding agents, and common
development and debugging utilities.
## Creating Sandboxes
### Basic Creation
```typescript
import { Sandbox } from "@vercel/sandbox";
const sandbox = await Sandbox.create({
name: "my-dev-env", // Optional, random if omitted. Unique per project.
resources: { vcpus: 4 }, // 2048 MB RAM per vCPU
ports: [3000], // Expose up to 15 ports
timeout: ms("10m"), // Default: 5 minutes
env: { NODE_ENV: "production" }, // Env vars inherited by all commands
tags: { env: "staging", team: "infra" }, // Up to 5 key:value tags
persistent: true, // Default: true. Auto-snapshots on stop, restores on resume.
snapshotExpiration: ms("7d"), // Default TTL for snapshots. Use 0 for no expiration.
region: "<region>", // Optional, defaults to iad1. Any Vercel region, e.g. sfo1, fra1, hnd1, syd1.
failoverRegions: ["<region>"], // Optional, e.g. ["sfo1", "fra1"]. Must not include `region`.
});
console.log(sandbox.name);
```
### Retrieve an Existing Sandbox
```typescript
// Retrieve by name. The sandbox will resume automatically the next time
// you run a command.
const sandbox = await Sandbox.get({ name: "my-dev-env" });
```
### Get-or-Create (Idempotent)
`Sandbox.getOrCreate` is the recommended pattern for long-lived sandboxes.
```typescript
const sandbox = await Sandbox.getOrCreate({
name: "my-workspace",
// Runs only the first time the sandbox is created.
onCreate: async (sbx) => {
await sbx.writeFiles([
{ path: "README.md", content: Buffer.from("# Hello") },
]);
await sbx.runCommand("npm", ["install"]);
},
// Runs every time the sandbox session is resumed (including after auto-resume).
onResume: async (sbx) => {
await sbx.runCommand({ cmd: "npm", args: ["run", "dev"], detached: true });
},
});
```
Behavior:
- If a sandbox with that `name` exists → resumes it and fires `onResume`.
- If it does not exist → creates a fresh sandbox and fires `onCreate`.
- If the sandbox exists but its snapshot expired → deletes the stale sandbox,
re-creates it with the same name, and fires `onCreate`.
### Re-warming on Resume
Use `onResume` to restart background services or rehydrate caches whenever a
persistent sandbox's session is resumed:
```typescript
const sandbox = await Sandbox.get({
name: "my-workspace",
onResume: async (sbx) => {
await sbx.runCommand({ cmd: "npm", args: ["run", "dev"], detached: true });
},
});
```
`onResume` also fires when a SDK call (e.g. `runCommand`, `writeFiles`)
auto-resumes a stopped sandbox.
### With Git Source
```typescript
const sandbox = await Sandbox.create({
source: {
type: "git",
url: "https://github.com/vercel/sandbox-example-next.git",
depth: 1, // Shallow clone (optional)
revision: "main", // Branch, tag, or commit (optional)
},
ports: [3000],
});
```
Git sources are cloned into a subdirectory named after the repository. For the
example above, run commands with `cwd: "sandbox-example-next"`.
### With Private Git Repository
```typescript
const sandbox = await Sandbox.create({
source: {
type: "git",
url: "https://github.com/org/private-repo.git",
username: process.env.GIT_USERNAME!,
password: process.env.GIT_TOKEN!, // Use PAT for password
},
});
```
### From Tarball
```typescript
const sandbox = await Sandbox.create({
source: {
type: "tarball",
url: "https://example.com/project.tar.gz",
},
ports: [3000],
});
```
### From a Snapshot
```typescript
const sandbox = await Sandbox.create({
source: {
type: "snapshot",
snapshotId: "snap_abc123",
},
ports: [3000],
});
```
### From a Custom Image (VCR)
Override the default with a [Vercel Container
Registry](https://vercel.com/docs/container-registry) (VCR) image stored in the
sandbox's project.
For a different distro or reproducible system tooling, prefer baking it into a
custom image over installing packages when the sandbox starts.
```typescript
const sandbox = await Sandbox.create({
image: "my-repo:v1",
ports: [3000],
});
```
`image` accepts a repository in the sandbox's project with an optional tag or
digest, or a fully-qualified VCR URL. A bare repository name resolves to the
`latest` tag:
```typescript
await Sandbox.create({ image: "my-repo" }); // latest tag
await Sandbox.create({ image: "my-repo:v1" }); // specific tag
await Sandbox.create({ image: "my-repo@sha256:..." }); // specific digest
await Sandbox.create({
image: "vcr.vercel.com/my-team/my-project/my-repo:v1", // fully-qualified
});
```
Push images to VCR with Docker-compatible tooling before referencing them. See the
[Container Registry docs](https://vercel.com/docs/container-registry) for push
instructions.
### Forking an Existing Sandbox
`Sandbox.fork` seeds a new sandbox from another sandbox's current snapshot
and copies its config (`resources`, `timeout`, `networkPolicy`, `tags`,
`ports`, `image`, `persistent`, `snapshotExpiration`, `keepLastSnapshots`,
and `env`). Any field you pass overrides the inherited value. If the source
has no current snapshot, the fork falls back to the source's base environment
plus the copied config. You can only fork a sandbox in a project you have
access to; forking an unknown source returns a 404. The fork runs in the
source's region unless you pass `region` (and optionally `failoverRegions`)
to override it.
```typescript
// Inherit everything from the source (env included)
const fork = await Sandbox.fork({ sourceSandbox: "prod-agent" });
// Override specific fields; the rest are copied from the source.
// A provided `env` fully replaces the source's env (no per-key merge).
const fork = await Sandbox.fork({
sourceSandbox: "prod-agent",
name: "forked-prod-agent",
resources: { vcpus: 4 },
env: { OPENAI_API_KEY: process.env.OPENAI_API_KEY! },
});
```
### When to fork a sandbox or a drive
Use `Sandbox.fork` when each worker needs its own sandbox environment, including
installed tools and files from the source sandbox's snapshot. Use `drive.fork`
when each worker needs an independent writable copy of persistent files.
`Sandbox.fork` does not inherit drive mounts; pass `mounts` if the fork needs a
drive.
Mount a drive when files should persist across sandbox runs. Many sandboxes
can mount `drive.snapshot()` for read-only access; each mount captures the
drive's files at mount time. Mount a new snapshot to see later writes. A drive
allows one read-write mount at a time. The sandbox and drive must be in the
same region. Write to a read-write mount once before forking a drive or
mounting its snapshot.
```typescript
import { Drive, Sandbox } from "@vercel/sandbox";
const baseDrive = await Drive.getOrCreate({ name: "agent-base-files" });
const seed = await Sandbox.create({
region: baseDrive.region,
mounts: { "/workspace": baseDrive },
});
await seed.writeFiles([
{ path: "/workspace/README.md", content: "starter" },
]);
await seed.stop();
// The source drive has now been written to and can be forked.
const workerDrive = await baseDrive.fork({ name: "agent-worker-1-files" });
const worker = await Sandbox.create({
region: workerDrive.region,
mounts: { "/workspace": workerDrive },
});
await worker.writeFiles([
{ path: "/workspace/result.txt", content: "worker" },
]);
await worker.stop();
```
The worker's writes stay on `workerDrive`; the base drive keeps the starter
files. Fork the base drive again with a different name for another worker.
### Auto-Dispose Pattern
Use `await using` for automatic cleanup:
```typescript
async function runInSandbox() {
await using sandbox = await Sandbox.create();
// Sandbox automatically stopped when scope exits
await sandbox.runCommand("echo", ["Hello"]);
}
```
## Running Commands
### Basic Command Execution
```typescript
const result = await sandbox.runCommand("npm", ["install"]);
if (result.exitCode !== 0) {
console.error("Install failed:", await result.stderr());
}
```
### With Options
```typescript
const result = await sandbox.runCommand({
cmd: "npm",
args: ["run", "build"],
cwd: "/vercel/sandbox/app",
env: { NODE_ENV: "production" },
sudo: false,
stdout: process.stdout, // Stream output
stderr: process.stderr,
});
```
### Detached Commands (Background Processes)
```typescript
// Start dev server in background
const devServer = await sandbox.runCommand({
cmd: "npm",
args: ["run", "dev"],
detached: true, // Returns immediately
stdout: process.stdout,
});
// Later: wait for completion or kill
const finished = await devServer.wait();
// Supported signals: SIGHUP, SIGINT, SIGQUIT, SIGKILL, SIGTERM, SIGCONT, SIGSTOP (or numeric)
await devServer.kill("SIGTERM");
```
### Root Access
```typescript
await sandbox.runCommand({
cmd: "apt-get",
args: ["update"],
sudo: true,
});
await sandbox.runCommand({
cmd: "apt-get",
args: ["install", "-y", "golang-go"],
sudo: true, // Execute as root
});
```
## File Operations
### Write Files
```typescript
await sandbox.writeFiles([
{
path: "/vercel/sandbox/config.json",
content: Buffer.from(JSON.stringify({ key: "value" })),
},
{
path: "/vercel/sandbox/script.sh",
GitHubで見るこの SKILL.md は非常に大きいため、SkillsMP では最初のセクションだけを表示しています。 GitHubで見る