In a Workers project that already uses Sandbox, or a new project from the Sandbox template:
npm i @cloudflare/sandbox@nextyarn add @cloudflare/sandbox@nextpnpm add @cloudflare/sandbox@nextbun add @cloudflare/sandbox@nextBuild and deploy the Worker and the sandbox container image from the same preview line.
import { Sandbox } from "@cloudflare/sandbox";
export { Sandbox };import { Sandbox } from "@cloudflare/sandbox";
export { Sandbox };Keep your wrangler Durable Object binding and container configuration. Preview-specific transport variables are not required.
exec() starts a program from argv — an array of the executable path or name, then its arguments. It waits until the sandbox can start the process, then returns a process handle. It does not wait for the process to exit.
Collect results with handle methods such as output(), or stream with logs().
import { getSandbox, proxyToSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
export default {
async fetch(request, env) {
const proxy = await proxyToSandbox(request, env);
if (proxy) return proxy;
const sandbox = getSandbox(env.Sandbox, "preview-demo");
const process = await sandbox.exec(["python3", "-c", "print(2 + 2)"]);
const output = await process.output({ encoding: "utf8" });
return Response.json({
id: process.id,
pid: process.pid,
stdout: output.stdout,
exitCode: output.exitCode,
});
},
};import { getSandbox, proxyToSandbox } from "@cloudflare/sandbox";
export { Sandbox } from "@cloudflare/sandbox";
type Env = {
Sandbox: DurableObjectNamespace<import("@cloudflare/sandbox").Sandbox>;
};
export default {
async fetch(request: Request, env: Env): Promise<Response> {
const proxy = await proxyToSandbox(request, env);
if (proxy) return proxy;
const sandbox = getSandbox(env.Sandbox, "preview-demo");
const process = await sandbox.exec(["python3", "-c", "print(2 + 2)"]);
const output = await process.output({ encoding: "utf8" });
return Response.json({
id: process.id,
pid: process.pid,
stdout: output.stdout,
exitCode: output.exitCode,
});
},
};Each argv entry is one argument to the process. The SDK does not run a shell and does not shell-escape argv. Spaces and special characters in an entry stay inside that argument.
Shell syntax (&&, pipes, redirects, globs) needs an explicit shell, with the script as its own argument:
const process = await sandbox.exec([
"/bin/bash",
"-lc",
"echo hello && uname -a",
]);
const { stdout } = await process.output({ encoding: "utf8" });const process = await sandbox.exec([
"/bin/bash",
"-lc",
"echo hello && uname -a",
]);
const { stdout } = await process.output({ encoding: "utf8" });await sandbox.exec(...)creates a process. It does not wait for exit. Useoutput(),waitForExit(), or other handle methods for completion.- Each
exec()is independent. Acdorexportin one call is not remembered in the next. - Pass
cwdandenvon eachexec()when you need them, or usesetEnvVarsfor sandbox-wide values. Refer to Environment variables. - A process runs only in the current container for that sandbox. After the container stops or is replaced, start a new process. Model: Sandbox lifecycle.
- Before production traffic, learn which failures are safe to retry: Errors and recovery.
- Sandbox lifecycle — sandbox ID, container, stop, and replace
- Process execution —
exec(), handles, and continuing work across requests - Errors and recovery — retries, interrupted calls, and stale handles
- Migrate — update an existing stable app
- API reference — processes, terminals, and errors
- Terminals — interactive PTY and browser connections
- Extensions