E2B.Sandbox reference
ConnectSandbox
Section titled “ConnectSandbox”Source:
packages/e2b/src/ConnectSandbox.ts
Work with one Sandbox declared in the stack, from a Worker,
Function or any other host: run commands, read and write files, open
terminals, call its ports, snapshot or fork it. The handle has the same
operations as the sandboxes CreateSandbox returns; its sandboxId and
url(port) are Effects, read at runtime.
A declared sandbox pauses when it is idle. With autoResume (the
default), E2B resumes it on the next request, to one of its ports or from
any call here. With autoResume: false, calls inside it (exec,
start, files, pty) fail with SandboxNotRunning until you call
resume().
The host gets its own E2B API key, minted at deploy and revoked when the host is destroyed. E2B keys are not scoped, so the key reaches the whole team; it is never the deployer’s own.
ConnectSandbox: Running commands in a dev box
Section titled “ConnectSandbox: Running commands in a dev box”const devBox = yield* E2B.ConnectSandbox(DevBox);return { fetch: Effect.gen(function* () { yield* devBox.resume({ timeout: "10 minutes" }); const test = yield* devBox.exec("git pull && npm test", { cwd: "/home/user/repo" }); return yield* HttpServerResponse.json(test); }),};ConnectSandbox: Streaming a process
Section titled “ConnectSandbox: Streaming a process”const build = yield* devBox.start("npm run build", { cwd: "/home/user/repo" });const output = build.output.pipe(Stream.map((chunk) => chunk.data));ConnectSandbox: Calling a program in the sandbox
Section titled “ConnectSandbox: Calling a program in the sandbox”Call port 3000
const port = yield* api.getTcpPort(3000);const response = yield* port.fetch(HttpClientRequest.get("/health"));Proxy the Worker’s request to port 3000
const port = yield* api.getTcpPort(3000);return yield* port.fetch(yield* HttpServerRequest);ConnectSandbox: Pausing it early
Section titled “ConnectSandbox: Pausing it early”yield* devBox.pause();ConnectSandboxHttp
Section titled “ConnectSandboxHttp”Source:
packages/e2b/src/ConnectSandboxHttp.tsKind: Layer · Provides:E2B.ConnectSandbox
HTTP implementation of ConnectSandbox: E2B’s control plane with
the host’s key, and envd inside the sandbox with the sandbox’s own token.
Works on any host.
ConnectSandboxHttp: Provide the layer
Section titled “ConnectSandboxHttp: Provide the layer”Effect.gen(function* () { const devBox = yield* E2B.ConnectSandbox(DevBox); // ...}).pipe(Effect.provide(E2B.ConnectSandboxHttp))CreateSandbox
Section titled “CreateSandbox”Source:
packages/e2b/src/CreateSandbox.ts
Create and manage E2B sandboxes from a Worker, Function or any other host.
E2B.CreateSandbox(base) creates sandboxes from a template or snapshot
declared in the stack; E2B.CreateSandbox() takes the template per call.
Both return the same client, whose calls take E2B’s own parameters.
Sandboxes created at run time are tagged with the stack, stage and
binding (alchemy::stack, alchemy::stage, alchemy::id in their E2B
metadata) and are not deleted when the stack is destroyed. List them by
those tags to clean them up:
sandboxes.list({ metadata: { "alchemy::stack": "my-app", "alchemy::stage": "prod" } }).
Metadata you pass to create merges underneath; it never replaces the
alchemy::* keys.
The host gets its own E2B API key, minted at deploy and revoked when the host is destroyed. E2B keys are not scoped, so the key reaches the whole team; it is never the deployer’s own.
CreateSandbox: Creating sandboxes
Section titled “CreateSandbox: Creating sandboxes”One sandbox per request, killed when the request ends
const sandboxes = yield* E2B.CreateSandbox(Agent);// in fetch:const sandbox = yield* Effect.acquireRelease( sandboxes.create({ timeout: 120 }), (sandbox) => Effect.ignore(sandbox.kill()),);const result = yield* sandbox.exec("node --version");A long-lived sandbox per task, found by metadata
const [existing] = yield* sandboxes.list({ metadata: { task }, state: ["running", "paused"] });const sandbox = existing ? yield* sandboxes.connect(existing.sandboxID) : yield* sandboxes.create({ metadata: { task }, autoPause: true, timeout: 1800 });CreateSandbox: Running commands
Section titled “CreateSandbox: Running commands”exec runs to completion and returns { exitCode, stdout, stderr }; a
non-zero exit is returned, not failed. A string runs in a login shell, an
array runs directly.
A shell line, an argument vector, stdin and a timeout
const test = yield* sandbox.exec("npm test", { cwd: "/home/user/app" });const version = yield* sandbox.exec(["node", "--version"]);const sorted = yield* sandbox.exec("sort", { stdin: "b\na\n" });const slow = yield* sandbox.exec("make", { timeout: "2 minutes" }); // E2B.ExecTimedOutStream a process, then wait for it
const build = yield* sandbox.start("npm run build", { cwd: "/home/user/app" });yield* build.output.pipe( Stream.runForEach((chunk) => Effect.log(new TextDecoder().decode(chunk.data))),);const { exitCode } = yield* build.wait;Closing the scope detaches: the process keeps running, and
sandbox.processes.attach({ pid }) picks it up again.
A terminal
const pty = yield* sandbox.pty.open({ cols: 120, rows: 40 });yield* pty.write("ls\n");yield* pty.resize({ cols: 160, rows: 48 });CreateSandbox: Network and secrets
Section titled “CreateSandbox: Network and secrets”const github = yield* GitHubToken;const sandbox = yield* sandboxes.create({ network: { allowOut: ["github.com", "*.github.com"], rules: { "api.github.com": [{ transform: { headers: { Authorization: `Bearer ${github.ref}` } } }] }, },});CreateSandboxHttp
Section titled “CreateSandboxHttp”Source:
packages/e2b/src/CreateSandboxHttp.tsKind: Layer · Provides:E2B.CreateSandbox
HTTP implementation of CreateSandbox: E2B’s control plane with the
team key, and envd inside each sandbox with that sandbox’s own token.
Works on any host.
CreateSandboxHttp: Provide the layer
Section titled “CreateSandboxHttp: Provide the layer”Effect.gen(function* () { const sandboxes = yield* E2B.CreateSandbox(Agent); // ...}).pipe(Effect.provide(E2B.CreateSandboxHttp))Sandbox
Section titled “Sandbox”Source:
packages/e2b/src/Sandbox.ts
An E2B sandbox the stack owns: one long-lived sandbox that pauses when it is idle and resumes when it is used, instead of one per request.
Use it for a workspace that outlives requests (an agent’s home, a dev
box) or to serve a template program at a stable URL. The sandbox runs for
timeout after it starts or resumes, then E2B pauses it with its memory
and files. A request to one of its URLs resumes it (autoResume), and so
does resume() on E2B.ConnectSandbox.
Alchemy stamps its stack, stage and logical ID into the sandbox’s metadata to recognise the sandboxes it owns.
Sandbox: Creating a Sandbox
Section titled “Sandbox: Creating a Sandbox”import * as E2B from "@alchemy.run/e2b";import * as Effect from "effect/Effect";
export const Node = E2B.Template("Node", { image: "node:22" });
export const DevBox = E2B.Sandbox("DevBox", { template: Node, timeout: "10 minutes",});Sandbox: Serving a template program
Section titled “Sandbox: Serving a template program”A template program starts when its sandbox boots. Declare one sandbox for it: each new build of the program replaces the sandbox, so it always runs the current one.
import * as E2B from "@alchemy.run/e2b";import * as Output from "alchemy/Output";import * as Effect from "effect/Effect";import Api from "./src/api.ts";
export const ApiSandbox = Effect.gen(function* () { const sandbox = yield* E2B.Sandbox("Api", { template: Api }); return { url: Output.interpolate`https://3000-${sandbox.sandboxId}.${sandbox.domain}` };});Sandbox: Private URLs
Section titled “Sandbox: Private URLs”const sandbox = yield* E2B.Sandbox("Private", { template: Node, network: { allowPublicTraffic: false },});// send sandbox.trafficAccessToken in the `e2b-traffic-access-token` headerSandbox: Using it at runtime
Section titled “Sandbox: Using it at runtime”const devBox = yield* E2B.ConnectSandbox(DevBox);// in fetch:yield* devBox.resume();const result = yield* devBox.exec("git pull && npm test", { cwd: "/home/user/repo" });Sandbox: Mounting volumes
Section titled “Sandbox: Mounting volumes”export const Cache = E2B.Volume("Cache", {});
export const Builder = E2B.Sandbox("Builder", { template: Node, mounts: [{ volume: Cache, path: "/cache" }],});Sandbox: Referencing a sandbox the stack doesn’t manage
Section titled “Sandbox: Referencing a sandbox the stack doesn’t manage”const shared = E2B.Sandbox.lookup({ sandboxId: "i1a2b3c4d5e6f7g8h9" });const box = yield* E2B.ConnectSandbox(shared);