Skip to content
Cloudflare Docs

Architecture

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:

TypeScript
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:

TypeScript
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 two 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.

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

WebSocket transport

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

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

{
"vars": {
"SANDBOX_TRANSPORT": "websocket"
},
}

The transport layer is transparent to your application code - all SDK methods work identically regardless of transport. See Transport modes for details on when to use each transport and configuration examples.

Request flow

When you execute a command:

TypeScript
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

WebSocket transport flow:

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

The WebSocket connection is established on first SDK call and reused for all subsequent operations, reducing overhead for high-frequency operations.