Skip to main content
This guide shows you how to set and manage environment variables in CWSandbox instances. Use environment variables to pass non-sensitive configuration values, such as log levels or project identifiers, into your sandboxes. You can set them on individual sandboxes, share them across sandboxes in a session, or scope them to remote functions.
Don’t use environment variables for sensitive information such as API keys, passwords, or other secrets. For sensitive values, use the Secret type instead. The server resolves secrets, and the client never sends them as raw values.

Basic usage

To make values available to processes running inside the sandbox, pass an environment_variables dictionary to Sandbox.run:
from cwsandbox import Sandbox

with Sandbox.run(
    environment_variables={"LOG_LEVEL": "info"},
) as sandbox:
    result = sandbox.exec([
        "python",
        "-c",
        "import os; print(os.environ.get('LOG_LEVEL'));",
    ]).result()
    print(result.stdout.strip())  # "info"

Session-level defaults

When you need the same variables in several sandboxes, define them once on a session instead of repeating them per sandbox. Individual sandboxes can override session defaults or add their own variables:
from cwsandbox import SandboxDefaults, Session

defaults = SandboxDefaults(
    environment_variables={
        "PROJECT_ID": "my-project",
        "LOG_LEVEL": "info",
    },
)

with Session(defaults) as session:
    with session.sandbox() as sb1:
        result = sb1.exec([
            "python",
            "-c",
            "import os; print(os.environ.get('LOG_LEVEL'));",
        ]).result()
        print(result.stdout.strip())  # "info"

    # Override LOG_LEVEL and add new variable
    with session.sandbox(
        environment_variables={
            "LOG_LEVEL": "debug",  # Override session default
            "MODEL_NAME": "gpt-4",  # Add new variable
        }
    ) as sb2:
        result = sb2.exec([
            "python",
            "-c",
            "import os; "
            "print(os.environ.get('PROJECT_ID')); "
            "print(os.environ.get('LOG_LEVEL')); "
            "print(os.environ.get('MODEL_NAME'));",
        ]).result()
        lines = result.stdout.strip().split("\n")
        print(lines)  # ["my-project", "debug", "gpt-4"]

Remote functions

Remote functions inherit environment variables from the session and can declare their own through the @session.function decorator. The SDK merges function-level variables with session defaults at call time:
with Session(defaults) as session:
    @session.function(environment_variables={"MODEL_VERSION": "v2.0"})
    def process(task_id: int) -> dict:
        import os
        return {
            "task": task_id,
            "project": os.environ.get("PROJECT_ID"),  # From session defaults
            "version": os.environ.get("MODEL_VERSION"),  # From function decorator
        }

    result = process.remote(42).result()
    print(result)  # {"task": 42, "project": "my-project", "version": "v2.0"}
Environment variables are passed by reference. Subsequent function calls reflect mutations to the dictionary after decoration, as shown in the following example.
env_vars = {"MODEL_VERSION": "v2.0"}

@session.function(environment_variables=env_vars)
def process(task_id: int) -> dict:
    import os
    return {"version": os.environ.get("MODEL_VERSION")}

result = process.remote(42).result()  # version: "v2.0"

env_vars["MODEL_VERSION"] = "v3.0"  # Mutate the dictionary

result = process.remote(42).result()  # version: "v3.0" (changed)
Last modified on May 29, 2026