@cloudflare/sandbox works with a container you start from a Durable Object. Its classes run helper processes in the running container through exec(). The package does not start, stop, or monitor the container.
For start(), exec(), snapshots, and the other methods of the container itself, refer to the Durable Object container API.
npm i @cloudflare/sandboxyarn add @cloudflare/sandboxpnpm add @cloudflare/sandboxbun add @cloudflare/sandboxEvery class in the package has these requirements. A class page lists any others.
-
The container image contains the helper binary at
/usr/local/bin/sandbox-shim. Copy it from thecloudflare/sandboximage whose tag matches the installed@cloudflare/sandboxversion:COPY --from=docker.io/cloudflare/sandbox:<VERSION> /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shimThe helper is a statically linked
linux/amd64binary. It runs in anylinux/amd64image. -
The Worker has the
nodejs_compatcompatibility flag. The package reads Linux error names throughnode:os. -
The container is running when a method is called.
This configuration meets every requirement. The Dockerfile copies the helper into a Debian Trixie image with Node.js 24, and sleep infinity keeps the container running:
FROM node:24-trixie-slim
COPY --from=docker.io/cloudflare/sandbox:1.0.0 /usr/local/bin/sandbox-shim /usr/local/bin/sandbox-shim
RUN mkdir /workspace
CMD ["sleep", "infinity"]The Wrangler configuration sets nodejs_compat, builds the Dockerfile as the image named workspace, and declares MyContainer as a Durable Object class:
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "sandbox-files",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-10-01",
"compatibility_flags": ["nodejs_compat"],
"containers": [
{
"class_name": "MyContainer",
"scheduling_policy": "durable_object",
"images": {
"workspace": {
"dockerfile": "./Dockerfile",
},
},
},
],
"durable_objects": {
"bindings": [
{
"class_name": "MyContainer",
"name": "MY_CONTAINER",
},
],
},
"exports": {
"MyContainer": {
"type": "durable-object",
"storage": "sqlite",
},
},
}"$schema" = "node_modules/wrangler/config-schema.json"
name = "sandbox-files"
main = "src/index.ts"
# Set this to today's date
compatibility_date = "2026-10-01"
compatibility_flags = [ "nodejs_compat" ]
[[containers]]
class_name = "MyContainer"
scheduling_policy = "durable_object"
[containers.images.workspace]
dockerfile = "./Dockerfile"
[[durable_objects.bindings]]
class_name = "MyContainer"
name = "MY_CONTAINER"
[exports.MyContainer]
type = "durable-object"
storage = "sqlite"The Durable Object starts the workspace image and passes the container to a class from the package:
import { Files } from "@cloudflare/sandbox";
import { DurableObject } from "cloudflare:workers";
const INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000;
export class MyContainer extends DurableObject {
container;
files;
constructor(ctx, env) {
super(ctx, env);
const container = ctx.container;
if (!container) {
throw new Error("The container binding is not configured");
}
this.container = container;
// ctx.container stays the same object while the Durable Object runs.
this.files = new Files(container);
// A restarted Durable Object sets the timeout again.
if (container.running) {
void ctx.blockConcurrencyWhile(() =>
container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS),
);
}
}
async listWorkspace() {
// Files does not start the container.
if (!this.container.running) {
this.container.start({
image: this.container.images.workspace,
enableInternet: false,
});
await this.container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS);
}
return this.files.readDirectory("/workspace");
}
}import { Files } from "@cloudflare/sandbox";
import { DurableObject } from "cloudflare:workers";
const INACTIVITY_TIMEOUT_MS = 10 * 60 * 1000;
export class MyContainer extends DurableObject<Env> {
private readonly container: Container;
private readonly files: Files;
constructor(ctx: DurableObjectState, env: Env) {
super(ctx, env);
const container = ctx.container;
if (!container) {
throw new Error("The container binding is not configured");
}
this.container = container;
// ctx.container stays the same object while the Durable Object runs.
this.files = new Files(container);
// A restarted Durable Object sets the timeout again.
if (container.running) {
void ctx.blockConcurrencyWhile(() =>
container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS),
);
}
}
async listWorkspace() {
// Files does not start the container.
if (!this.container.running) {
this.container.start({
image: this.container.images.workspace,
enableInternet: false,
});
await this.container.setInactivityTimeout(INACTIVITY_TIMEOUT_MS);
}
return this.files.readDirectory("/workspace");
}
}For more information about building images, refer to images.