Skip to content

Architecture

Last updated View as MarkdownAgent setup

Sandbox SDK lets you execute untrusted code safely from your Workers. It combines three Cloudflare technologies to provide secure, stateful, and isolated execution:

  • Workers - Your application logic that calls the Sandbox SDK
  • Durable Objects - Persistent sandbox instances with unique identities
  • Containers - Isolated Linux environments where code actually runs

Architecture overview

flowchart TB
    accTitle: Sandbox SDK Architecture
    accDescr: Three-layer architecture showing how Cloudflare Sandbox SDK combines Workers, Durable Objects, and Containers for secure code execution

    subgraph UserSpace["<b>Your Worker</b>"]
        Worker["Application code using the methods exposed by the Sandbox SDK"]
    end

    subgraph SDKSpace["<b>Sandbox SDK Implementation</b>"]
        DO["Sandbox Durable Object routes requests & maintains state"]
        Container["Isolated Ubuntu container executes untrusted code safely"]

        DO -->|HTTP API| Container
    end

    Worker -->|RPC call via the Durable Object stub returned by `getSandbox`| DO

    style UserSpace fill:#fff8f0,stroke:#f6821f,stroke-width:2px
    style SDKSpace fill:#f5f5f5,stroke:#666,stroke-width:2px,stroke-dasharray: 5 5
    style Worker fill:#ffe8d1,stroke:#f6821f,stroke-width:2px
    style DO fill:#dce9f7,stroke:#1d8cf8,stroke-width:2px
    style Container fill:#d4f4e2,stroke:#17b26a,stroke-width:2px

Layer 1: Client SDK

The developer-facing API you use in your Workers:

import { getSandbox } from "@cloudflare/sandbox";

const sandbox = getSandbox(env.Sandbox, "my-sandbox");
const result = await sandbox.exec("python script.py");

Purpose: Provide a clean, type-safe TypeScript interface for all sandbox operations.

Layer 2: Durable Object

Manages sandbox lifecycle and routing:

export class Sandbox extends DurableObject<Env> {
	// Extends Cloudflare Container for isolation
	// Routes requests between client and container
	// Manages preview URLs and state
}

Purpose: Provide persistent, stateful sandbox instances with unique identities.

Why Durable Objects:

  • Persistent identity - Same sandbox ID always routes to same instance
  • Container management - Durable Object owns and manages the container lifecycle
  • Geographic distribution - Sandboxes run close to users
  • Automatic scaling - Cloudflare manages provisioning

Layer 3: Container Runtime

Executes code in isolation with full Linux capabilities.

Purpose: Safely execute untrusted code.

Why containers:

  • VM-based isolation - Each sandbox runs in its own VM
  • Full environment - Ubuntu Linux with Python, Node.js, Git, etc.

Communication transports

The SDK supports three transport protocols for communication between the Durable Object and container:

HTTP transport (default)

Each SDK method makes a separate HTTP request to the container API. Simple, reliable, and works for most use cases.

// Default behavior - uses HTTP
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
await sandbox.exec("python script.py");

RPC transport

Multiplexes all SDK calls over a single persistent connection. It avoids subrequest limits when making many concurrent operations.

Enable RPC transport by setting the SANDBOX_TRANSPORT variable in your Worker's configuration:

{
	"vars": {
		"SANDBOX_TRANSPORT": "rpc"
	},
}
[vars]
SANDBOX_TRANSPORT = "rpc"

WebSocket transport

WebSocket transport is deprecated. Use RPC transport for new applications.

The transport layer is transparent to your application code — all SDK methods work identically regardless of transport. For details on when to use each transport and configuration examples, refer to Transport modes.

Request flow

When you execute a command:

await sandbox.exec("python script.py");

HTTP transport flow:

  1. Client SDK validates parameters and sends HTTP request to Durable Object
  2. Durable Object authenticates and forwards HTTP request to container
  3. Container Runtime validates inputs, executes command, captures output
  4. Response flows back through all layers with proper error transformation

RPC transport flow:

  1. Client SDK validates parameters and sends the request to the Durable Object
  2. Durable Object maintains the persistent connection to the container and multiplexes concurrent requests
  3. Container Runtime adapts RPC messages to HTTP-style request and response handling
  4. Response flows back over the same connection with proper error transformation

The Durable Object establishes the persistent connection to the container on first SDK call and reuses it for all subsequent operations, reducing overhead for high-frequency operations.

Was this helpful?