Upgrade from 0.2
Move code from Sandbox SDK 0.2 to 1.0. Covers createSandbox, run, files, processes, ports, snapshots, the local provider, and removed providers.
1.0 keeps the idea of 0.2, one API over many sandbox providers, and changes most of the surface. Commands return richer results and never throw on a non-zero exit. Sandboxes can be found again by key. Processes survive a server restart. local() now runs Docker. This page maps each 0.2 call to its 1.0 form.
Overview of changes
createSandboxtakes the provider as its first argument.stop()is split intoclose()anddestroy().runresults have new fields, andtimeoutistimeoutMs.files.textandfiles.readmerge intofiles.read.processes.startbecomesbox.start, with names, readiness, and logs.ports.exposebecomesbox.preview.snapshots.*becomesbox.snapshot()andcreateSandbox(provider, { from }).local()runs Docker instead of an AgentOS VM.- Some providers and helpers are gone.
1. createSandbox
Before
await using sandbox = await createSandbox({ provider: e2b(), cwd: "/workspace", env: { CI: "1" } });
After
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
await using box = await createSandbox(e2b(), { env: { CI: "1" } });
Key changes
- The provider is the first argument. Options are the second and all optional.
cwdis gone. Every sandbox works in/workspace. Passcwdper command.- New options:
key,size,secrets,network,ports,idleTimeoutMs,timeoutMs,labels, andfrom. See Sandboxes and keys. withSandbox(options, callback)is removed. Useawait using.
2. stop, close, and destroy
Before
await sandbox.stop();
After
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
const box = await createSandbox(e2b());
await box.destroy();
Key changes
destroy()does whatstop()did: it deletes the sandbox.close()is new. It detaches and leaves the sandbox running.await usingcallsclose()when you passed akeyanddestroy()otherwise. In 0.2 it always stopped the sandbox. See Lifecycle and cleanup.
3. run
Before
const result = await sandbox.run("npm test", { timeout: 60_000 });
if (!result.success) console.log(result.stderr);
await sandbox.run({ command: "git", args: ["checkout", branch] });
After
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
const branch = "main";
await using box = await createSandbox(e2b());
const result = await box.run("npm test", { timeoutMs: 60_000 });
if (!result.ok) console.log(result.output);
await box.$`git checkout ${branch}`;
Key changes
successis nowok.exitCodeisnullwhen the command was killed.- New fields:
output(both streams interleaved),truncated,timedOut,cwd,command. timeoutistimeoutMsand defaults to 120 seconds. Output is capped at 1 MB per stream.- A timeout resolves with
timedOut: trueinstead of throwing. - The
{ command, args }form is gone. Use the$tag, which escapes every value. runcan be iterated to stream output. See Running commands.
4. files
| 0.2 | 1.0 |
|---|---|
files.text(path) |
files.read(path) |
files.read(path) (bytes) |
files.read(path, { as: "bytes" }) |
files.write(path, value) |
files.write(path, value), or files.write({ ...many }) |
files.list(path) |
files.list(path, { recursive, glob }) |
files.mkdir(path) |
Not needed. write creates directories. |
files.remove(path) |
files.remove(path, { recursive }) |
files.exists(path) |
files.exists(path) |
write accepts a string or a Uint8Array. ArrayBuffer, Blob, and streams are no longer accepted. List entries now carry modifiedAt, and name is gone (take it from path).
New in 1.0: edit, stat, upload, download, search, watch, mark, and changes, plus box.git. See Files and git.
5. processes
Before
const proc = await sandbox.processes.start("npm run dev");
for await (const event of proc.output()) console.log(event.data);
await proc.kill();
After
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
await using box = await createSandbox(e2b());
const dev = await box.start("npm run dev", { name: "dev", ready: { port: 3000 } });
for await (const line of dev.lines()) {
console.log(line.text);
if (line.text.includes("ready")) break;
}
await dev.stop();
Key changes
- Every process has a
name. Find it again withbox.process(name), even from another server. readywaits for a port, an HTTP response, or a log line beforestartreturns.output()becomeslines()andlogs(), both resumable from a cursor.kill()becomesstop(), which sends SIGTERM and then SIGKILL.write()to a process’s stdin is removed. Pass input up front withbox.run(command, { stdin }). The API reservesbox.terminal()for interactive input, but no built-in provider implements it in 1.0.
6. ports
Before
const port = await sandbox.ports.expose(3000);
console.log(port.url);
After
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
await using box = await createSandbox(e2b(), { ports: [3000] });
const preview = await box.preview(3000, { waitMs: 10_000 });
console.log(preview.url, preview.headers);
Key changes
previewreturnsurl, plusheadersandexpiresAtwhen the provider needs them. Sendheaderswith every request.public,authenticated, andrequest()are gone.- Declare ports in
createSandbox(provider, { ports }). Vercel and Local require it. Local declares port 3000 when you leave it out.
7. snapshots
| 0.2 | 1.0 |
|---|---|
snapshots.create() |
box.snapshot() |
snapshots.restore(id) |
createSandbox(provider, { from: id }) |
snapshots.delete(id) |
Call the provider’s API through box.native |
snapshot() exists only on providers that support it, so TypeScript reports a call on one that doesn’t. In 0.2 that was a runtime error.
8. local()
In 0.2, local() ran an AgentOS VM bundled with the package. In 1.0 it runs a Docker container from node:22-bookworm. Install Docker and make sure docker info works. The AgentOS dependency is gone, so installs are much smaller. See Local.
9. Removed
- Providers: Ascii Box has no 1.0 adapter. Pin
@opencoredev/sandbox-sdk@0.2if you depend on it, or write an adapter with the provider contract from@opencoredev/sandbox-sdk/provider. Upstash Box, Railway, Tenki, boxd, and Freestyle have new 1.0 adapters. - Helpers:
withSandbox,supports,requireCapability,capabilityMode,isSandboxError,redactSensitive. Usebox.capabilities.has(...)anderror instanceof SandboxError. sandbox.rawis nowbox.native.- The
/eveintegration. The agent tool subpaths are/ai,/mastra, and/openai. See Give your agent a sandbox.
Complete example
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
await using sandbox = await createSandbox({ provider: e2b() });
await sandbox.files.write("app/index.js", "console.log('hi')");
const result = await sandbox.run("node index.js", { cwd: "app", timeout: 10_000 });
console.log(result.success, result.stdout);
const port = await sandbox.ports.expose(3000);
console.log(port.url);
import { createSandbox } from "@opencoredev/sandbox-sdk";
import { e2b } from "@opencoredev/sandbox-sdk/e2b";
await using box = await createSandbox(e2b(), { ports: [3000] });
await box.files.write("app/index.js", "console.log('hi')");
const result = await box.run("node index.js", { cwd: "app", timeoutMs: 10_000 });
console.log(result.ok, result.stdout);
const preview = await box.preview(3000);
console.log(preview.url);
Stuck on something this page doesn’t cover? Open an issue on GitHub.