Transport modes
Configure how the Sandbox SDK communicates with containers using transport modes.
The Sandbox SDK supports two 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.
- WebSocket transport - All SDK operations are multiplexed over a single persistent WebSocket connection.
Use WebSocket transport when your Worker or Durable Object makes many SDK operations per request. This avoids hitting 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.
WebSocket 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):
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 WebSocket transport (1 subrequest):
// Identical code - transport is configured via environment variableawait 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");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 is the default and requires no additional configuration.
Enable WebSocket transport by adding SANDBOX_TRANSPORT to your Worker's vars:
{ "name": "my-sandbox-worker", "main": "src/index.ts", "compatibility_date": "2025-10-13", "vars": { "SANDBOX_TRANSPORT": "websocket" }, "containers": [ { "class_name": "Sandbox", "image": "./Dockerfile", }, ], "durable_objects": { "bindings": [ { "class_name": "Sandbox", "name": "Sandbox", }, ], },}name = "my-sandbox-worker"main = "src/index.ts"compatibility_date = "2025-10-13"
[vars]SANDBOX_TRANSPORT = "websocket"
[[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.
HTTP transport:
- Creates a new HTTP request for each SDK operation
- No persistent connection
- Each request is independent and stateless
WebSocket 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
Both transports support streaming operations (like exec() with real-time output):
- HTTP transport - Uses Server-Sent Events (SSE)
- WebSocket transport - Uses WebSocket streaming messages
Your code remains identical regardless of transport mode.
Both 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
| Scenario | Recommended transport |
|---|---|
| Many SDK operations per request | WebSocket |
| Running inside Workers or Durable Objects | WebSocket |
| Approaching subrequest limits | WebSocket |
| Simple, infrequent sandbox usage | HTTP (default) |
| Debugging or inspecting individual requests | HTTP (default) |
Switching between transports requires no code changes.
Add SANDBOX_TRANSPORT to your wrangler.jsonc:
{ "vars": { "SANDBOX_TRANSPORT": "websocket" },}[vars]SANDBOX_TRANSPORT = "websocket"Then deploy:
npx wrangler deployRemove the SANDBOX_TRANSPORT variable (or set it to "http"):
{ "vars": { // Remove SANDBOX_TRANSPORT or set to "http" },}vars = { }- Wrangler configuration - Complete Worker configuration
- Environment variables - Passing configuration to sandboxes
- Workers subrequest limits - Understanding subrequest limits
- Architecture - How Sandbox SDK components communicate