Skip to content
Cloudflare Docs

Environment variables

Pass configuration, secrets, and runtime settings to your sandboxes using environment variables.

SDK configuration 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.

SANDBOX_TRANSPORT

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"
},
}

See Transport modes for a complete guide including when to use each transport, performance considerations, and migration instructions.

Three ways to set environment variables

The Sandbox SDK provides three methods for setting environment variables, each suited for different use cases:

1. Sandbox-level with setEnvVars()

Set environment variables globally for all commands in the sandbox:

TypeScript
const sandbox = getSandbox(env.Sandbox, "my-sandbox");
// Set once, available for all subsequent commands
await sandbox.setEnvVars({
DATABASE_URL: env.DATABASE_URL,
API_KEY: env.API_KEY,
});
await sandbox.exec("python migrate.py"); // Has DATABASE_URL and API_KEY
await sandbox.exec("python seed.py"); // Has DATABASE_URL and API_KEY
// Unset variables by passing undefined
await 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:

TypeScript
await sandbox.setEnvVars({
API_KEY: 'new-key', // Sets API_KEY
OLD_SECRET: undefined, // Unsets OLD_SECRET
DEBUG_MODE: null // Unsets DEBUG_MODE
});

2. Per-command with exec() options

Pass environment variables for a specific command:

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

3. Session-level with createSession()

Create an isolated session with its own environment variables:

TypeScript
const session = await sandbox.createSession({
env: {
DATABASE_URL: env.DATABASE_URL,
SECRET_KEY: env.SECRET_KEY,
},
});
// All commands in this session have these vars
await session.exec("python migrate.py");
await session.exec("python seed.py");

Use when: You need isolated execution contexts with different environment variables running concurrently.

Unsetting environment variables

The Sandbox SDK supports unsetting environment variables by passing undefined or null values. This enables idiomatic JavaScript patterns for managing configuration:

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

Use cases for unsetting

Remove sensitive data after use:

TypeScript
// Use a temporary token
await sandbox.setEnvVars({ TEMP_TOKEN: 'abc123' });
await sandbox.exec('curl -H "Authorization: $TEMP_TOKEN" api.example.com');
// Clean up the token
await sandbox.setEnvVars({ TEMP_TOKEN: undefined });

Conditional environment setup:

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

TypeScript
// Unset to fall back to container's default NODE_ENV
await sandbox.setEnvVars({ NODE_ENV: undefined });

Common patterns

Pass Worker secrets to sandbox

Securely pass secrets from your Worker to the sandbox. First, set secrets using Wrangler:

Terminal window
wrangler secret put OPENAI_API_KEY
wrangler secret put DATABASE_URL

Then pass them to your sandbox:

TypeScript
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 });
},
};

Combine default and specific variables

TypeScript
const defaults = { NODE_ENV: "production", LOG_LEVEL: "info" };
await sandbox.exec("npm start", {
env: { ...defaults, PORT: "3000", API_KEY: env.API_KEY },
});

Multiple isolated sessions

Run different tasks with different environment variables concurrently:

TypeScript
// Production database session
const prodSession = await sandbox.createSession({
env: { DATABASE_URL: env.PROD_DATABASE_URL },
});
// Staging database session
const stagingSession = await sandbox.createSession({
env: { DATABASE_URL: env.STAGING_DATABASE_URL },
});
// Run migrations on both concurrently
await Promise.all([
prodSession.exec("python migrate.py"),
stagingSession.exec("python migrate.py"),
]);

Configure transport mode

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.

Bucket mounting credentials

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:

  1. Go to R2 > Overview in the Cloudflare dashboard
  2. Select Manage R2 API Tokens
  3. Create a token with Object Read & Write permissions
  4. Copy the Access Key ID and Secret Access Key

Set credentials as Worker secrets:

Terminal window
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 Key

Mount buckets with automatic credential detection:

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

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

Environment variable precedence

When the same variable is set at multiple levels, the most specific level takes precedence:

  1. Command-level (highest) - Passed to exec() or startProcess() options
  2. Sandbox or session-level - Set with setEnvVars()
  3. Container default - Built into the Docker image with ENV
  4. System default (lowest) - Operating system defaults

Example:

TypeScript
// In Dockerfile: ENV NODE_ENV=development
// Sandbox-level
await sandbox.setEnvVars({ NODE_ENV: "staging" });
// Command-level overrides all
await sandbox.exec("node app.js", {
env: { NODE_ENV: "production" }, // This wins
});