Skip to content
Cloudflare Docs

Environment variables

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

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

Use when: You need the same environment variables for multiple commands.

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.

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
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"),
]);

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