Skip to main content
Sandboxes are short-lived, isolated CPU environments that you create on demand, run commands in, and tear down when you’re done. They’re built for running untrusted code: code generated by an AI agent, code submitted by your users, or one-off scripts you don’t want touching your own infrastructure. You manage sandboxes through the REST API v2. Each sandbox runs a container image you choose (or a default image), starts in seconds, and is billed per second until it terminates.

Quickstart

Create a sandbox, run a command, and terminate it.

API reference

Endpoints and fields for the /v2/sandboxes resource.

When to use a sandbox

Use a sandbox when you need a clean, disposable environment for a short task:
  • An AI agent needs to execute the code it writes.
  • Your application runs code or commands supplied by end users.
  • You want to test a script or package in isolation before running it elsewhere.
For long-running workloads, GPU compute, or persistent development environments, use Pods instead. For request-driven inference that scales with traffic, use Serverless.

Isolation

Every sandbox runs under gVisor, a user-space kernel that intercepts the container’s system calls. Code inside a sandbox can’t reach the host machine or other tenants’ sandboxes, so you can run code you don’t trust.

Images and templates

You can start a sandbox in three ways:
  • Default image: send an empty request body ({}) and the sandbox runs Runpod’s default sandbox image.
  • Container image: set image to any public image, for example python:3.12-slim. For a private image, also set registry to the ID of one of your saved container registry credentials (from /v2/registries).
  • Template: set templateId to a sandbox template. Runpod provides curated templates, such as Ubuntu and Harbor.
image and templateId can’t be used together.
Review question: Which templates will be available to customers at Beta, and should the docs list their IDs? Remove this box before merging.
If you create a sandbox from an image without a start command, the container runs a keepalive process so it stays up for you to run commands in. To run your own main process, set cmd (and optionally entrypoint) in exec form, for example ["python", "-m", "http.server", "8080"].

Lifecycle

A sandbox moves through these states: POST /v2/sandboxes returns 201 with the new sandbox, usually still in the CREATING state. Poll GET /v2/sandboxes/{id} until state is RUNNING before you send commands.

Retry creates safely

Send an Idempotency-Key header with each create request. If the response is lost and you retry with the same key and the same body, the API returns the sandbox the first request created instead of creating (and billing for) a second one. If the first create failed, for example because no capacity was available, that key is spent: retrying with it returns 409. Retry a failed create with a new key.

Termination is final

A terminated sandbox can’t be restarted. Its record stays readable through GET /v2/sandboxes/{id}, with terminationReason and terminatedAt set, so you can see why and when it stopped. To run more work, create a new sandbox. Terminating a sandbox that is already terminated succeeds, so it’s safe to retry DELETE /v2/sandboxes/{id}.

Timeouts

Every sandbox has two clocks. Whichever runs out first terminates the sandbox and stops billing:
  • Idle timeout (idleTimeoutSeconds): how long the sandbox can go without activity. Running a command and keeping a log stream open both count as activity. The deadline is reported in idleExpiresAt.
  • Maximum lifetime (maxLifetimeSeconds): a hard ceiling on total lifetime, counted from creation. The deadline is reported in expiresAt.
Review question: Are these the production defaults and maximums (idle 10 min / max 2 h, lifetime 1 h / max 24 h)? Remove this box before merging.
If you omit a value, the default applies. Values above the maximum are clamped to it, and idle timeouts under 90 seconds are raised to 90. Check idleTimeoutSeconds and maxLifetimeSeconds in the response to see the values actually applied. You can change both while a sandbox is running:
Terminate sandboxes explicitly when you’re finished, including in your error-handling paths. Don’t rely on a timeout to stop billing.

Network access

By default, a sandbox has open outbound internet access. Code inside it can reach any host on the internet, for example to install packages or call external APIs. Restricting outbound traffic is opt-in and is not yet available to all accounts. When it is, you’ll be able to set egressMode on create to DENY_ALL (no outbound access) or ALLOW_LIST (only the hostnames in egressAllowlist). Until restriction is enabled for your account, any mode other than ALLOW_ALL returns 400.
Review question: Will egress restriction (DENY_ALL, ALLOW_LIST) be enforced and available to customers by Beta, or should this stay “coming soon”? Remove this box before merging.

Exposed ports

To reach a service running inside a sandbox, list its ports in ports when you create the sandbox (up to 15):
  • http ports are reached through the Runpod proxy at the url returned in the sandbox’s ports list. Treat the URL as opaque.
  • tcp and udp ports are reached directly at the returned ip and publicPort.

Storage

Each sandbox has an ephemeral container disk, 10 GB by default (set disk to change it). It’s deleted when the sandbox terminates. To keep data, mount an existing volume with mounts:
  • mounts.network: a network volume, mounted at /workspace by default. Place the sandbox in the volume’s data center.
  • mounts.global: a global volume, mounted at /workspace-global by default.
Review question: Will the default user be able to write to network volumes in EU-RO-1 (MooseFS, AI-262) by Beta? If not, should network volumes be left out of the docs? Remove this box before merging.

Connect over SSH

Set startSsh: true on create to inject the SSH public keys registered on your account. Connect using the details in the sandbox’s ssh field. For a direct connection, also expose 22/tcp in ports. Only images that start sshd from the PUBLIC_KEY environment variable support this; all Runpod official images do.

Environment variables and secrets

Pass environment variables in env. You can reference a Runpod secret with {{ RUNPOD_SECRET_name }}; a create that references a secret you can’t access is rejected.
env is returned as written in API responses, so anyone who can read the sandbox can see plain values. Use secret references for credentials instead of plain values.

Compute and pricing

Sandboxes run on CPU compute. Set the CPU flavor and vCPU count in cpu, or omit it to use the standard sandbox configuration. Memory and container disk limits scale with the flavor. The cpu and compute fields in the sandbox response show what’s backing it. Sandboxes are billed per second from creation until termination, at the rate shown in compute.costPerHr (USD per hour). Your account needs enough balance to start a sandbox; otherwise, create returns 402.
Review question: Should the docs publish the per-unit rates (0.035pervCPU−hour,0.035 per vCPU-hour, 0.0175 per GB-hour) at Beta? Will there be a launch credit? Also: which data centers offer sandboxes at Beta? Remove this box before merging.
Review question: Will sandbox concurrency be a separate cap or part of the shared per-plan vCPU pool (64 / 256 / 512)? What numbers and plan names should the docs show? Remove this box before merging.

Labels

Attach labels (string key-value pairs) when you create a sandbox to track which job, user, or environment it belongs to. You can filter GET /v2/sandboxes by one or more labels, written as key=value.

Known limitations

These limitations reflect current behavior and will change as the feature matures:
  • The first command can return 409. RUNNING means compute is allocated, not that the container has finished starting. Until it has, commands and log streams return 409 with code sandbox_starting. Retry after a short delay.
  • Commands are capped at about 4 seconds. A command still running at the cap is stopped and returns exitCode: null. For longer work, run the command with background: true, write its output to a file, and read the file with a later command.
  • A sandbox can show RUNNING after its container exits. If a command returns 409 with code container_exited, terminate the sandbox and create a new one.
  • /tmp uses memory. Writing large files to /tmp counts against the sandbox’s memory and can stop it. Write large files elsewhere, such as your home directory or a mounted volume.
  • Some terminal UIs don’t render. Tool compatibility follows the gVisor version Runpod runs, and some full-screen terminal apps may not display correctly.

Next steps

Last modified on October 19, 2026