Skip to content

Transport modes

Configure how the Sandbox SDK communicates with containers using transport modes.

Overview

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

  • HTTP transport (default) - Each SDK operation makes a separate HTTP request to the container.
  • NEW: RPC transport - All SDK operations are multiplexed over a single persistent WebSocket connection. Will replace HTTP as the default transport in future. Available since 0.9.1.
  • Deprecated: WebSocket transport - All SDK operations are multiplexed over a single persistent WebSocket. Superseded by RPC transport which uses an improved protocol.

When to use RPC transport

Use the RPC transport when your Worker or Durable Object makes many SDK operations per request. This avoids hitting subrequest limits.

Subrequest limits

Cloudflare Workers have subrequest limits that apply when making requests to external services, including container API calls:

  • Workers Free: 50 subrequests per request
  • Workers Paid: 1,000 subrequests per request

With HTTP transport (default), each SDK operation (exec(), readFile(), writeFile(), etc.) consumes one subrequest. Applications that perform many sandbox operations in a single request can hit these limits.

How RPC transport helps

RPC transport establishes a single persistent connection to the container and multiplexes all SDK operations over it. The WebSocket upgrade counts as one subrequest regardless of how many operations you perform afterwards.

Example with HTTP transport (4 subrequests):

TypeScript
await sandbox.exec("python setup.py");
await sandbox.writeFile("/app/config.json", config);
await sandbox.exec("python process.py");
const result = await sandbox.readFile("/app/output.txt");

Same code with RPC transport (1 subrequest):

TypeScript
// Identical code - transport is configured via environment variable
await sandbox.exec("python setup.py");
await sandbox.writeFile("/app/config.json", config);
await sandbox.exec("python process.py");
const result = await sandbox.readFile("/app/output.txt");

RPC transport also removes the 32 MiB limitation that the HTTP transport has. Pass a ReadableStream instance to the writeFile() method.

JavaScript
const req = await fetch("https://example.com/archive.tar.gz");
await sandbox.writeFile("/archive.tar.gz", req.body);

Configuration

Set the SANDBOX_TRANSPORT environment variable in your Worker's configuration. The SDK reads this from the Worker environment bindings (not from inside the container).

HTTP transport (default)

HTTP transport is the default and requires no additional configuration.

RPC transport

Enable RPC transport by adding SANDBOX_TRANSPORT to your Worker's vars:

JSONC
{
"name": "my-sandbox-worker",
"main": "src/index.ts",
// Set this to today's date
"compatibility_date": "2026-05-07",
"vars": {
"SANDBOX_TRANSPORT": "rpc"
},
"containers": [
{
"class_name": "Sandbox",
"image": "./Dockerfile",
},
],
"durable_objects": {
"bindings": [
{
"class_name": "Sandbox",
"name": "Sandbox",
},
],
},
}

No application code changes are needed. The SDK automatically uses the configured transport for all operations.

Transport behavior

Connection lifecycle

HTTP transport:

  • Creates a new HTTP request for each SDK operation
  • No persistent connection
  • Each request is independent and stateless

RPC transport:

  • Establishes a WebSocket connection on the first SDK operation
  • Maintains the persistent connection for all subsequent operations
  • Connection is closed when the sandbox sleeps or is evicted
  • Automatically reconnects if the connection drops

Streaming support

All transports support streaming operations (like exec() with real-time output):

  • HTTP transport - Uses Server-Sent Events (SSE)
  • RPC transport - Uses WebSocket streaming messages

Your code remains identical regardless of transport mode.

Error handling

All transports provide identical error handling behavior. The SDK automatically retries on transient errors (like 503 responses) with exponential backoff.

WebSocket-specific behavior:

  • Connection failures trigger automatic reconnection
  • The SDK transparently handles WebSocket disconnections
  • In-flight operations are not lost during reconnection

Choosing a transport

We expect the RPC transport to replace the default HTTP transport in a future release. New functionality may support only the RPC transport. Switching to use it now will avoid migrations in the future.

Migration guide

Switching between transports requires no code changes.

Switch from HTTP to RPC

Add SANDBOX_TRANSPORT to your wrangler.jsonc:

JSONC
{
"vars": {
"SANDBOX_TRANSPORT": "rpc"
},
}

Then deploy:

Terminal window
npx wrangler deploy

Switch from RPC to HTTP

Remove the SANDBOX_TRANSPORT variable (or set it to "http"):

JSONC
{
"vars": {
// Remove SANDBOX_TRANSPORT or set to "http"
},
}

Switch from deprecated WebSocket to RPC

Set the SANDBOX_TRANSPORT variable to "rpc":

JSONC
{
"vars": {
"SANDBOX_TRANSPORT": "rpc"
},
}