> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blaxel.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Sandbox variables and secrets

> Configure environment variables and secrets in Blaxel sandboxes to securely manage API keys, credentials, and runtime configuration values.

## Environment variables

There are multiple ways to configure environment variables in Blaxel sandboxes.

<Note>
  On the new sandbox generation, you can update environment variables on a running sandbox, or give them a new value when you [fork a sandbox](/Sandboxes/Fork#fork-with-new-environment-variables). Both are in preview. Other parts of the runtime spec, such as memory, cannot be changed on a running sandbox.
</Note>

### When building new sandbox images

Environment variables defined in the sandbox image with the `ENV` Dockerfile directive are available in every sandbox created from it.

```dockerfile theme={null}
FROM blaxel/base-image:latest

ENV NODE_ENV=production
ENV PORT=3000
```

<Warning>
  Never add secrets in a Dockerfile.
</Warning>

This also applies when creating sandbox images with the [declarative image builder](/Sandboxes/Templates#blaxel-sdk):

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { ImageInstance } from "@blaxel/core";

  const sandbox = await ImageInstance.fromRegistry("node:20-alpine")
    .workdir("/app")
    .env({
      NODE_ENV: "production",
      PORT: "3000",
    })
    .build({ name: "my-sandbox", memory: 4096 });
  ```

  ```python Python theme={null}
  from blaxel.core import ImageInstance

  sandbox = await (
      ImageInstance.from_registry("node:20-alpine")
      .workdir("/app")
      .env(NODE_ENV="production", PORT="3000")
      .build(name="my-sandbox", memory=4096)
  )
  ```
</CodeGroup>

### When instantiating sandboxes from existing images

When instantiating sandboxes from existing images, any environment variables defined in the base image are automatically available. Additional environment variables can be set using the following methods.

#### Set variables at sandbox creation time

Pass `envs` as an array of name/value objects when creating a sandbox with the Blaxel SDKs. These are set as environment variables and are available to every process running inside the deployed sandbox by default (although they can be overridden by process-level variables, discussed in the next section).

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SandboxInstance } from "@blaxel/core";

  const sandbox = await SandboxInstance.createIfNotExists({
    name: "my-sandbox",
    image: "blaxel/base-image:latest",
    region: "us-pdx-1",
    envs: [
      { name: "NODE_ENV", value: "production" },
      { name: "PORT", value: "3000" },
    ],
  });
  ```

  ```python Python theme={null}
  from blaxel.core import SandboxInstance

  sandbox = await SandboxInstance.create_if_not_exists({
    "name": "my-sandbox",
    "image": "blaxel/base-image:latest",
    "region": "us-pdx-1",
    "envs": [
      { "name": "NODE_ENV", "value": "production" },
      { "name": "PORT", "value": "3000" },
    ],
  })
  ```
</CodeGroup>

#### Update variables on an existing sandbox

Read the sandbox, change its `envs` list, and update it. A variable you drop from the list is removed, and a variable you add or change takes the new value.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { getSandbox, updateSandbox } from "@blaxel/core";

  const { data: sandbox } = await getSandbox({
    path: { sandboxName: "my-sandbox" },
    throwOnError: true,
  });

  sandbox.spec.runtime.envs = [
    { name: "NODE_ENV", value: "staging" },
    { name: "PORT", value: "3000" },
  ];

  await updateSandbox({
    path: { sandboxName: "my-sandbox" },
    body: sandbox,
    throwOnError: true,
  });
  ```

  ```python Python theme={null}
  from blaxel.core.client.api.compute.get_sandbox import asyncio as get_sandbox
  from blaxel.core.client.api.compute.update_sandbox import asyncio as update_sandbox
  from blaxel.core.client.client import client
  from blaxel.core.client.models.env import Env

  sandbox = await get_sandbox("my-sandbox", client=client)
  sandbox.spec.runtime.envs = [
      Env(name="NODE_ENV", value="staging"),
      Env(name="PORT", value="3000"),
  ]

  await update_sandbox("my-sandbox", client=client, body=sandbox)
  ```

  ```bash HTTP API theme={null}
  curl -X PUT https://api.blaxel.ai/v0/sandboxes/my-sandbox \
    -H "Authorization: Bearer $BL_API_KEY" \
    -H "X-Blaxel-Workspace: my-workspace" \
    -H "Content-Type: application/json" \
    -d @sandbox.json
  ```
</CodeGroup>

The update replaces the whole sandbox definition, so send back the sandbox you read with only its `envs` changed. When the variables are the only change, the new environment reaches the sandbox while it keeps running: processes you start afterwards read the new values, and processes already running keep the environment they were started with. Change anything else at the same time, memory for example, and the sandbox is redeployed instead, which restarts it and loses its state.

To keep the state of a sandbox and run it with a different environment, [fork it with new variables](/Sandboxes/Fork#fork-with-new-environment-variables) instead.

### When executing sandbox processes

Environment variables can also be set at process execution, applicable only to that specific process.

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { SandboxInstance } from "@blaxel/core";

  const sandbox = await SandboxInstance.get("my-sandbox");

  const process = await sandbox.process.exec({
    command: "node server.js",
    env: {
      PORT: "8080",
      LOG_LEVEL: "debug",
    },
  });
  ```

  ```python Python theme={null}
  from blaxel.core import SandboxInstance

  sandbox = await SandboxInstance.get("my-sandbox")

  process = await sandbox.process.exec({
    "command": "node server.js",
    "env": {
      "PORT": "8080",
      "LOG_LEVEL": "debug",
    },
  })
  ```
</CodeGroup>

## Secrets

### Use proxy injection (recommended)

The recommended way to inject secrets into a sandbox is with the Blaxel proxy. This intercepts outbound HTTPS requests from the sandbox and injects secrets server-side using `{{SECRET:name}}` placeholders. The sandbox code never sees raw API keys or credentials.

See the [proxy routing with secrets injection](/Sandboxes/Proxy-secrets-injection) documentation for examples.

### Use a .env.build file

Build variables let you pass secrets and configuration values into the Docker build phase without exposing them at runtime. This is useful when your build process needs credentials that should never appear inside the deployed sandbox.

Create a `.env.build` file in the root of your project for build secrets. A common example of this is installing private npm packages, which require an `NPM_TOKEN` during `npm install`. Variables defined here are injected during the build phase only and are never persisted in the runtime environment.

```bash .env.build theme={null}
MY_SECRET_BUILD_VAR=I_AM_A_SECRET
```

<Tip>
  Use the `--build-env-file` argument to `bl deploy` to specify a custom file name or path instead of the default `.env.build`.
</Tip>

<Warning>
  Ensure that `.env.build` is ignored during commits to avoid accidentally making secrets public.
</Warning>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.