Each exec() and createTerminal() starts an independent process. Shell export in one process does not apply to the next launch. Configure process environment with the container image, setEnvVars, and per-launch env.
Use environment variables for non-secret configuration (paths, feature flags, NODE_ENV, and similar). Do not put live API keys or other long-lived credentials into the sandbox. To call external services that need credentials, use outbound traffic handlers so secrets stay in the Worker.
When a process starts, the runtime builds its environment from:
- The container environment (image
ENVand defaults). - Names from
setEnvVars, when you useexec()(described in the next section). - The
envoption on that launch, if you pass one.
Later launches do not keep overlays from earlier launches. A command that runs export FOO=bar inside one process does not change the next exec().
Worker bindings in your fetch handler are not process environment variables. Only values you pass through setEnvVars or launch env appear inside the process (and those should not be long-lived secrets).
setEnvVars(envVars: Record<string, string | undefined>): Promise<void>| Value | Effect |
|---|---|
| string | Set this environment variable for later exec() launches |
undefined |
Remove a previously stored variable |
On each exec(), the SDK merges stored names into that process’s environment at launch.
Stored names live in the sandbox Durable Object’s memory. They are not written to the container filesystem and are not part of a backup. After the Durable Object is evicted or replaced, call setEnvVars again if you still need those names, or pass env on each exec().
const sandbox = getSandbox(env.Sandbox, "user-123");
await sandbox.setEnvVars({
NODE_ENV: "production",
APP_HOME: "/workspace/app",
LOG_LEVEL: "info",
});
const migrate = await sandbox.exec(["python", "migrate.py"], {
cwd: "/workspace/app",
});
await migrate.output({ encoding: "utf8" });
const seed = await sandbox.exec(["python", "seed.py"], {
cwd: "/workspace/app",
});
await seed.output({ encoding: "utf8" });
await sandbox.setEnvVars({
LOG_LEVEL: "debug",
TEMP_FLAG: undefined,
});const sandbox = getSandbox(env.Sandbox, "user-123");
await sandbox.setEnvVars({
NODE_ENV: "production",
APP_HOME: "/workspace/app",
LOG_LEVEL: "info",
});
const migrate = await sandbox.exec(["python", "migrate.py"], {
cwd: "/workspace/app",
});
await migrate.output({ encoding: "utf8" });
const seed = await sandbox.exec(["python", "seed.py"], {
cwd: "/workspace/app",
});
await seed.output({ encoding: "utf8" });
await sandbox.setEnvVars({
LOG_LEVEL: "debug",
TEMP_FLAG: undefined,
});const process = await sandbox.exec(["node", "app.js"], {
cwd: "/workspace/app",
env: {
NODE_ENV: "production",
PORT: "3000",
},
});const process = await sandbox.exec(["node", "app.js"], {
cwd: "/workspace/app",
env: {
NODE_ENV: "production",
PORT: "3000",
},
});| Behavior | Detail |
|---|---|
| Scope | This launch only |
| Merge order | Container environment, then setEnvVars, then this env |
| Side effects | Does not update setEnvVars storage |
Omit env when sandbox-wide names (and the container environment) are enough.
const terminal = await sandbox.createTerminal({
command: ["bash"],
cwd: "/workspace",
env: {
TERM: "xterm-256color",
APP_HOME: "/workspace/app",
},
});const terminal = await sandbox.createTerminal({
command: ["bash"],
cwd: "/workspace",
env: {
TERM: "xterm-256color",
APP_HOME: "/workspace/app",
},
});The terminal’s launch env overlays the container environment for that terminal only. Pass the names the terminal needs on createTerminal.
Inside an interactive shell, export applies for the life of that terminal. It does not apply to later exec() calls. Refer to Terminals.
Code inside the sandbox should not hold live provider credentials. Keep secrets in the Worker and intercept outbound HTTP(S) with outboundByHost (and related policy such as enableInternet / allowedHosts). The sandbox can send ordinary requests—or placeholders client libraries require—while the Worker attaches real credentials before the request leaves your account.
Refer to Handle outbound traffic, including securely injecting credentials. For Workers bindings (KV, R2, and similar) reached by hostname from the sandbox, refer to Connect to Workers bindings.