Skip to content

Get started

Last updated View as MarkdownAgent setup

1. Install the preview package

In a Workers project that already uses Sandbox, or a new project from the Sandbox template:

npm i @cloudflare/sandbox@next

Build and deploy the Worker and the sandbox container image from the same preview line.

2. Export your Sandbox class

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.

3. Run a process

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" });

4. How this differs from the stable package

  • await sandbox.exec(...) creates a process. It does not wait for exit. Use output(), waitForExit(), or other handle methods for completion.
  • Each exec() is independent. A cd or export in one call is not remembered in the next.
  • Pass cwd and env on each exec() when you need them, or use setEnvVars for 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.

Next

Was this helpful?