Environment variables
Pass configuration, secrets, and runtime settings to your sandboxes using environment variables.
These environment variables configure how the Sandbox SDK behaves. Set these as Worker vars in your wrangler.jsonc file. The SDK reads them from the Worker's environment bindings.
| Type | "http" | "websocket" |
| Default | "http" |
Controls the transport protocol for SDK-to-container communication. WebSocket transport multiplexes all operations over a single persistent connection, avoiding subrequest limits when performing many SDK operations per request.
{ "vars": { "SANDBOX_TRANSPORT": "websocket" },}[vars]SANDBOX_TRANSPORT = "websocket"See Transport modes for a complete guide including when to use each transport, performance considerations, and migration instructions.
The Sandbox SDK provides three methods for setting environment variables, each suited for different use cases:
Set environment variables globally for all commands in the sandbox:
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
// Set once, available for all subsequent commandsawait sandbox.setEnvVars({ DATABASE_URL: env.DATABASE_URL, API_KEY: env.API_KEY,});
await sandbox.exec("python migrate.py"); // Has DATABASE_URL and API_KEYawait sandbox.exec("python seed.py"); // Has DATABASE_URL and API_KEY
// Unset variables by passing undefinedawait sandbox.setEnvVars({ API_KEY: "new-key", // Updates API_KEY OLD_SECRET: undefined, // Unsets OLD_SECRET});Use when: You need the same environment variables for multiple commands.
Unsetting variables: Pass undefined or null to unset environment variables:
await sandbox.setEnvVars({ API_KEY: 'new-key', // Sets API_KEY OLD_SECRET: undefined, // Unsets OLD_SECRET DEBUG_MODE: null // Unsets DEBUG_MODE});Pass environment variables for a specific command:
await sandbox.exec("node app.js", { env: { NODE_ENV: "production", PORT: "3000", },});
// Also works with startProcess()await sandbox.startProcess("python server.py", { env: { DATABASE_URL: env.DATABASE_URL, },});Use when: You need different environment variables for different commands, or want to override sandbox-level variables.
Create an isolated session with its own environment variables:
const session = await sandbox.createSession({ env: { DATABASE_URL: env.DATABASE_URL, SECRET_KEY: env.SECRET_KEY, },});
// All commands in this session have these varsawait session.exec("python migrate.py");await session.exec("python seed.py");Use when: You need isolated execution contexts with different environment variables running concurrently.
The Sandbox SDK supports unsetting environment variables by passing undefined or null values. This enables idiomatic JavaScript patterns for managing configuration:
await sandbox.setEnvVars({ // Set new values API_KEY: 'new-key', DATABASE_URL: env.DATABASE_URL,
// Unset variables (removes them from the environment) OLD_API_KEY: undefined, TEMP_TOKEN: null});Before this change: Passing undefined values would throw a runtime error.
After this change: undefined and null values run unset VARIABLE_NAME in the shell.
Remove sensitive data after use:
// Use a temporary tokenawait sandbox.setEnvVars({ TEMP_TOKEN: 'abc123' });await sandbox.exec('curl -H "Authorization: $TEMP_TOKEN" api.example.com');
// Clean up the tokenawait sandbox.setEnvVars({ TEMP_TOKEN: undefined });Conditional environment setup:
await sandbox.setEnvVars({ API_KEY: env.API_KEY, DEBUG_MODE: env.NODE_ENV === 'development' ? 'true' : undefined, PROFILING: env.ENABLE_PROFILING ? 'true' : undefined});Reset to system defaults:
// Unset to fall back to container's default NODE_ENVawait sandbox.setEnvVars({ NODE_ENV: undefined });Securely pass secrets from your Worker to the sandbox. First, set secrets using Wrangler:
wrangler secret put OPENAI_API_KEYwrangler secret put DATABASE_URLThen pass them to your sandbox:
import { getSandbox } from "@cloudflare/sandbox";
interface Env { Sandbox: DurableObjectNamespace; OPENAI_API_KEY: string; DATABASE_URL: string;}
export default { async fetch(request: Request, env: Env): Promise<Response> { const sandbox = getSandbox(env.Sandbox, "user-sandbox");
// Option 1: Set globally for all commands await sandbox.setEnvVars({ OPENAI_API_KEY: env.OPENAI_API_KEY, DATABASE_URL: env.DATABASE_URL, }); await sandbox.exec("python analyze.py");
// Option 2: Pass per-command await sandbox.exec("python analyze.py", { env: { OPENAI_API_KEY: env.OPENAI_API_KEY, }, });
return Response.json({ success: true }); },};const defaults = { NODE_ENV: "production", LOG_LEVEL: "info" };
await sandbox.exec("npm start", { env: { ...defaults, PORT: "3000", API_KEY: env.API_KEY },});Run different tasks with different environment variables concurrently:
// Production database sessionconst prodSession = await sandbox.createSession({ env: { DATABASE_URL: env.PROD_DATABASE_URL },});
// Staging database sessionconst stagingSession = await sandbox.createSession({ env: { DATABASE_URL: env.STAGING_DATABASE_URL },});
// Run migrations on both concurrentlyawait Promise.all([ prodSession.exec("python migrate.py"), stagingSession.exec("python migrate.py"),]);Set SANDBOX_TRANSPORT in your Worker's vars to switch between HTTP and WebSocket transport. See Transport modes for details on when and how to configure each transport.
When mounting S3-compatible object storage, the SDK uses s3fs-fuse under the hood, which requires AWS-style credentials. For R2, generate API tokens from the Cloudflare dashboard and provide them using AWS environment variable names:
Get R2 API tokens:
- Go to R2 > Overview ↗ in the Cloudflare dashboard
- Select Manage R2 API Tokens
- Create a token with Object Read & Write permissions
- Copy the Access Key ID and Secret Access Key
Set credentials as Worker secrets:
wrangler secret put AWS_ACCESS_KEY_ID# Paste your R2 Access Key ID
wrangler secret put AWS_SECRET_ACCESS_KEY# Paste your R2 Secret Access KeyMount buckets with automatic credential detection:
import { getSandbox } from "@cloudflare/sandbox";
interface Env { Sandbox: DurableObjectNamespace; AWS_ACCESS_KEY_ID: string; AWS_SECRET_ACCESS_KEY: string;}
export default { async fetch(request: Request, env: Env): Promise<Response> { const sandbox = getSandbox(env.Sandbox, "data-processor");
// Credentials automatically detected from environment await sandbox.mountBucket("my-r2-bucket", "/data", { endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com", });
// Access mounted bucket using standard file operations await sandbox.exec("python", { args: ["process.py", "/data/input.csv"] });
return Response.json({ success: true }); },};The SDK automatically detects AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY from your Worker's environment when you call mountBucket() without explicit credentials.
Pass credentials explicitly (if using custom secret names):
await sandbox.mountBucket("my-r2-bucket", "/data", { endpoint: "https://YOUR_ACCOUNT_ID.r2.cloudflarestorage.com", credentials: { accessKeyId: env.R2_ACCESS_KEY_ID, secretAccessKey: env.R2_SECRET_ACCESS_KEY, },});See Mount buckets guide for complete bucket mounting documentation.
When the same variable is set at multiple levels, the most specific level takes precedence:
- Command-level (highest) - Passed to
exec()orstartProcess()options - Sandbox or session-level - Set with
setEnvVars() - Container default - Built into the Docker image with
ENV - System default (lowest) - Operating system defaults
Example:
// In Dockerfile: ENV NODE_ENV=development
// Sandbox-levelawait sandbox.setEnvVars({ NODE_ENV: "staging" });
// Command-level overrides allawait sandbox.exec("node app.js", { env: { NODE_ENV: "production" }, // This wins});- Transport modes - Configure HTTP vs WebSocket transport
- Wrangler configuration - Setting Worker-level environment
- Secrets - Managing sensitive data
- Sessions API - Session-level environment variables
- Security model - Understanding data isolation