GPU Sandboxes
GPU sandboxes, their capabilities, use cases, and architecture.
GPU sandboxes are GPU virtual machines (VMs). Each sandbox has one or more dedicated NVIDIA or AMD GPUs attached to it on shared physical hardware. The hardware enforces the boundary and isolation between sandboxes. Code inside it can train and fine-tune models, serve inference, and run any program built on CUDA, NVIDIA's platform for general-purpose computing on GPUs. Each GPU sandbox has dedicated GPUs, is always ephemeral, and can save its state as a checkpoint that includes GPU memory.
| Term | Description |
|---|---|
| GPU | A processor built for parallel computation, used for machine learning, simulation, and graphics. |
| VRAM | The memory on a GPU. Models, weights, and intermediate results live in VRAM while the GPU works on them. |
| CUDA | NVIDIA's platform and libraries for running general-purpose programs on NVIDIA GPUs. PyTorch, vLLM, and most ML frameworks use it. |
| NVIDIA driver | The software that controls NVIDIA GPUs. Programs reach a GPU through requests to this driver. |
| Checkpoint | A saved copy of a running GPU sandbox's processes, memory, and GPU memory that a new GPU sandbox can resume from. |
Use cases
Use GPU sandboxes for GPU code you cannot trust or must keep isolated.
- Inference: a model in VRAM, served for example with vLLM or SGLang, answers requests through a preview URL or from code in the sandbox.
- Training and fine-tuning: a job trains on whole GPUs that no other sandbox shares, with the dataset and outputs in the sandbox. The shared memory directory is sized at 40 GiB per GPU for PyTorch data loaders and NCCL.
- AI-generated GPU code: an agent writes CUDA, PyTorch, or other GPU code, runs it on a real GPU, and reads the result, without access to your infrastructure.
- Evaluation and benchmarks: each model, checkpoint, or test case runs on its own GPU in a clean environment, so results do not depend on another run.
- Reinforcement learning (RL): policies that need a GPU for rollouts or updates run in isolated environments that are created and deleted per run.
- Pausing expensive work: a long job is checkpointed to release its GPU and resumed later, or on another GPU of the same model, from the point it was saved.
- Fast model starts: a checkpoint taken after a model loads holds the model in GPU memory. A new GPU sandbox restored from it serves the model without loading it again.
- Image generation and graphics: RTX GPUs run image generation, rendering, graphics workloads, and CUDA development at a lower cost than data center GPUs.
Create a GPU sandbox
Create a GPU sandbox from the dashboard or programmatically.
- Go to Daytona Sandboxes ↗
- Click Create
- Select GPU sandbox
- Click Create
curl 'https://api.daytona.com/sandboxes/gpu' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{"image": "pytorch", "gpu_host": 1}'The following example sets the remaining fields:
# Source: image is a registered image name or img_ id
# GPUs: gpu_host is a count, or gpu is an array of host PCI addresses instead
# Resources: cpu in cores, mem_mib and scratch_mib in MiB
# Networking: ports entries are {vm_port, proto?}
curl 'https://api.daytona.com/sandboxes/gpu' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "pytorch",
"gpu_host": 1,
"name": "my-gpu-sandbox",
"labels": { "team": "ml", "run": "42" },
"user": "root",
"cpu": 4,
"mem_mib": 16384,
"scratch_mib": 102400,
"ports": [{ "vm_port": 8000 }],
"env": { "HF_HOME": "/root/.cache/huggingface" },
"secrets": ["HF_TOKEN"],
"region": "us",
"lifecycle": {
"idle_timeout_secs": 3600,
"on_idle_timeout": "delete",
"timeout_secs": 86400,
"on_timeout": "delete"
},
"idempotency_key": "run-42-create"
}'| Field | Type | Description |
|---|---|---|
image | string | Sets the registered image that the sandbox starts from, by name or img_ ID. This field is required. |
gpu_host | integer | Sets the number of GPUs to attach. The runner selects the physical cards. Set exactly one of gpu_host and gpu. |
gpu | array | Passes GPUs through to the sandbox by host PCI address. Set exactly one of gpu and gpu_host. |
name | string | Sets the display name. If omitted, a name is generated. |
labels | object | Attaches key-value metadata to the sandbox. |
user | string | Sets the default OS user inside the sandbox. The default is root. |
cpu | number | Sets the guaranteed CPU cores as a float. The value is raised to at least one core per 4 GiB of guaranteed memory. The default is 0.125. |
vcpus | integer | Sets an integer CPU request. It applies only if cpu is absent. The default is 2. |
mem_mib | integer | Sets the guaranteed memory in MiB. The default is 1024. |
scratch_mib | integer | Sets the guaranteed writable disk in MiB. The default is 512. |
ports | array | Forwards inbound ports to the sandbox. |
env | object | Sets environment variables inside the sandbox. |
secrets | array | Attaches project secrets by name. The sandbox sees each secret as an opaque placeholder. |
region | string | Sets the region or global region slug. The default is the project default. |
lifecycle | object | Sets the lifecycle policy with timeout_secs and on_timeout, and idle_timeout_secs and on_idle_timeout. The only action is delete. By default, there is no idle timeout, and the wall-clock timeout uses the organization or platform default, if one is enabled. |
idempotency_key | string | Makes a retried create return the same sandbox. You can also send it as the Idempotency-Key header. |
The response has the following fields:
| Field | Description |
|---|---|
status | The status is often pending, because the server holds the request for at most 3 seconds by default. Poll GET /sandboxes/{sandboxId}?wait=running until the sandbox is running. |
GPUs
Daytona provides the following GPU models. Availability depends on the region.
| GPU | Description |
|---|---|
| NVIDIA H100 | Data center GPU for training and serving large models. The common choice for fine-tuning and for inference with vLLM or SGLang. |
| NVIDIA H200 | Same compute as the H100 with more and faster memory. Holds larger models and longer context windows in VRAM, which raises inference throughput for memory-bound workloads. |
| NVIDIA B200 | Data center GPU for training and serving large models. More compute and VRAM than the H200, and it adds FP4 precision for inference. |
| NVIDIA B300 | Data center GPU for the largest models. Its VRAM fits models that need several H100s on one GPU, and it adds FP4 precision for inference. |
| NVIDIA RTX PRO 6000 | Workstation and server GPU. Serves and fine-tunes mid-size models at a lower price than data center GPUs, and runs rendering and graphics workloads. |
| NVIDIA RTX 4090 | Consumer GPU. Runs small models, quantized inference, image generation, and CUDA development at the lowest cost. |
| NVIDIA RTX 5090 | Consumer GPU. Same uses as the RTX 4090 with more VRAM, more memory bandwidth, and FP4 support. |
| AMD Instinct MI355X | AMD data center GPU for training and inference of large models. Programs use ROCm, AMD's platform for GPU computing, instead of CUDA. PyTorch and vLLM ship ROCm builds. |
GPU allocation
A create request asks for a number of GPUs. Daytona places the sandbox on a host with that many free GPUs of the region's kind and assigns whole physical GPUs to it. A GPU is never shared: each belongs to exactly one sandbox until that sandbox is deleted.
GPUs are reserved exactly. A host with three GPUs runs at most three single-GPU sandboxes, and a request that no host in the region can satisfy fails instead of sharing a GPU. Processor and memory on GPU hosts follow the same guarantees and resource limits as Linux sandboxes; only GPUs are never shared or oversubscribed.
Lifecycle
Every GPU sandbox moves through a lifecycle. A GPU sandbox can have several different states. Each state reflects the status of your sandbox. A GPU sandbox transitions between states in response to user actions, or automatically when one of its timeouts elapses.
| Feature | Ephemeral |
|---|---|
| Stop and start | ✗ |
| Pause and resume | ✗ |
| Fork | ✗ |
| Delete | ✓ |
| Filesystem persistence | ✗ |
| Memory persistence | ✗ |
| Memory snapshot | ✓ checkpoint |
| Filesystem snapshot | ✗ |
| Spot (Preemption) | ✗ |
| Network policy | ✗ |
| Desktop | ✗ |
Every GPU sandbox supports wait for state, delete, timeouts, and lifecycle policy updates. GPU sandboxes are always ephemeral: the writable filesystem exists until the sandbox is deleted, and deleting the sandbox releases its GPUs. GPU sandboxes do not support stop, start, pause, resume, or fork. To keep the state of a GPU sandbox, take a checkpoint. Restoring a checkpoint creates a new GPU sandbox that moves through the same states as a create.
| State | Description |
|---|---|
queued | The create request is recorded and waits to be published for placement. |
pending | The create request is accepted and the sandbox is queued for placement on a host with free GPUs. |
assigned | The sandbox is placed on a host and its GPUs are reserved. |
booting | The root filesystem is assembled, the GPUs are attached, and the sandbox is starting. |
running | The sandbox is running and ready to accept requests. |
deleting | The sandbox is being deleted. |
deleted | The sandbox and its writable filesystem are removed, and its GPUs are released. |
failed | The sandbox could not start or hit an unrecoverable error. |
lost | The host running the sandbox was lost. A checkpoint taken earlier can still be restored. |
| Initial state | Target state | Trigger |
|---|---|---|
queued | pending | The create or restore request is published for placement. |
pending | assigned | The sandbox is placed on a host with enough free GPUs. |
assigned | booting | The host assembles the root filesystem and attaches the GPUs. |
booting | running | The sandbox daemon answers, the sandbox's secrets are delivered, and the sandbox accepts requests. |
| any state | deleting | A delete is requested, or a timeout elapses. |
deleting | deleted | The sandbox is removed and its GPUs are released. |
| any active state | failed | The sandbox fails to start or hits an unrecoverable error. |
running | lost | The host running the sandbox is lost. |
Wait for state
Wait until a GPU sandbox reaches a target state. The wait stops early when the sandbox reaches a state from which the target is no longer reachable, such as failed or deleted. The SDKs use their own state names, so the SDK started state corresponds to the running state in the CLI and API. A GPU sandbox never enters the stopping, pausing, or paused states.
# Block until the sandbox is started; returns the sandbox
sandbox.wait(until="started", timeout=60)
# Block until the sandbox is destroyed
sandbox.wait_for_state(["destroyed"], timeout=60)| Parameter | Type | Description |
|---|---|---|
until | str | Sets the one state that wait() waits for. wait_for_state() takes a list and returns on any of its states. The default is "started". |
timeout | float | Sets the wait limit in seconds. None or 0 waits without a limit. When the timeout elapses, both methods raise RequestTimeoutError. The default is 60 for wait() and None for wait_for_state(). |
Delete
Delete a GPU sandbox to tear down its virtual machine. Deletion works in any state, and the call returns once teardown starts. The sandbox moves from deleting to deleted when the teardown finishes. Daytona releases the sandbox's GPUs and discards its writable filesystem, memory, and GPU memory. Checkpoints taken from the sandbox remain. To keep the state of a running sandbox, create a checkpoint before you delete it.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
sandbox.delete()Timeouts
Daytona deletes a GPU sandbox automatically when one of its two timers elapses. Each timer pairs an interval in seconds with the action it fires. Set both timers at create in the lifecycle object, and change them later through update lifecycle policy.
| Timer | Purpose | Fires after | Default |
|---|---|---|---|
| Timeout | Cap how long a sandbox runs | The sandbox has been running for the interval, active or not | Project or platform default |
| Idle timeout | Delete a sandbox that is not in use | The sandbox has had no activity for the interval | Project default, or off |
Delete is the only valid action on both timers:
| Action | GPU sandbox |
|---|---|
| Stop | ✗ |
| Pause | ✗ |
| Delete | ✓ |
Auto-delete is not a separate setting. It is the idle timeout with the delete action. The stop and pause actions and wake on request are not available for GPU sandboxes. Because every timer on a GPU sandbox deletes it, a lifecycle policy update and an idle timer reset require the delete:sandboxes permission in addition to write:sandboxes.
Timeout
The timeout is a wall-clock budget. It starts when the sandbox is created. Activity does not extend it. The timeout fires in any state. Once set, the timeout cannot be cleared.
When the timeout is omitted at create, Daytona applies the ephemeral block of the project's lifecycle defaults. Without a project default, Daytona applies the platform default timeout of 300 seconds, if the platform default is enabled. An explicit timeout must not exceed the organization maximum, 86,400 seconds (24 hours) unless the organization sets a different maximum.
When the action is omitted, it defaults to delete.
# Delete the sandbox 2 hours after it entered running
curl 'https://api.daytona.com/sandboxes/gpu' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "pytorch",
"gpu_host": 1,
"lifecycle": { "timeout_secs": 7200, "on_timeout": "delete" }
}'Idle timeout
The idle timeout fires after the sandbox has had no activity for the interval. Activity is any request through the toolbox API, preview URLs, and SSH, and any lifecycle operation on the sandbox. The idle timeout is off by default unless the project sets one, has a minimum of 60 seconds, and requires an action. The action fires within about 2 minutes after the interval elapses.
Auto-delete
Delete a GPU sandbox after a period of inactivity. Deleting the sandbox releases its GPUs.
curl 'https://api.daytona.com/sandboxes/gpu' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{
"image": "pytorch",
"gpu_host": 1,
"lifecycle": { "idle_timeout_secs": 3600, "on_idle_timeout": "delete" }
}'Reset the idle timer
Reset the idle timer of a GPU sandbox to keep it alive while it does work that Daytona does not count as activity. The reset counts as activity, so the idle countdown restarts from now. The timeout is not affected.
The reset succeeds in any state, whether or not an idle timeout is set. It never moves the timer backwards: when newer activity arrives at the same time, the newer activity wins.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
lifecycle = sandbox.reset_idle_timer()
print(lifecycle.idle_timeout_at)Update lifecycle policy
Update the timeouts of an existing GPU sandbox. Omitted fields keep their current values. Delete is the only valid action, as listed in timeouts.
from daytona import Daytona
from daytona.v2 import DISABLED
daytona = Daytona()
sandbox = daytona.v2.get("{sandboxId}")
# Delete the sandbox after 30 minutes without activity; omitted fields keep their current value
lifecycle = sandbox.set_lifecycle(idle_timeout_secs=1800, on_idle_timeout="delete")
print(lifecycle.idle_timeout_secs, lifecycle.on_idle_timeout)
# Re-anchor the timeout to 1 hour from now
lifecycle = sandbox.set_lifecycle(timeout_secs=3600)
print(lifecycle.timeout_at)
# Clear the idle timeout
lifecycle = sandbox.set_lifecycle(idle_timeout_secs=DISABLED)Checkpoint
A checkpoint saves the processes, memory, and GPU memory of a running GPU sandbox under a name. A new GPU sandbox restored from the checkpoint continues from the point the checkpoint was taken, instead of booting and loading its models again. GPU sandboxes are always ephemeral, so a checkpoint is the only way to keep the state of a GPU sandbox.
| Captured | Contents |
|---|---|
| Processes and memory | Each process's memory, open files, and execution point. |
| GPU memory | VRAM, including loaded models, via NVIDIA's cuda-checkpoint. |
| Filesystem lineage | The source image, so the restore has the same software. |
The sandbox is frozen while the checkpoint is written. Freezing and restoring take longer the more GPU memory the sandbox uses, because GPU memory is copied out and back in. The capture runs in the background: the checkpoint starts as pending and becomes ready when its capture job finishes.
Daytona places a restore only on a host where it can succeed:
- The host has the same GPU model and the same NVIDIA driver branch as the checkpoint.
- The host has enough free VRAM for the checkpoint's GPU memory, checked before the restore.
The restored sandbox can run on a different physical GPU from the original. It gets a new address, and it keeps the operating system user of the original sandbox.
# Capture the processes, memory, and GPU memory of the running sandbox
curl 'https://api.daytona.com/sandboxes/{sandboxId}/snapshots' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{"name": "my-checkpoint"}'
# Block until the checkpoint is ready
curl 'https://api.daytona.com/snapshots/{snapshotId}?wait=ready' \
--header 'Authorization: Bearer YOUR_API_KEY'
# Continue from the checkpoint in a new GPU sandbox
curl 'https://api.daytona.com/sandboxes/gpu/from-snapshot' \
--request POST \
--header 'Content-Type: application/json' \
--header 'Authorization: Bearer YOUR_API_KEY' \
--data '{"snapshot": "my-checkpoint"}'The capture request returns the pending checkpoint and the job that captures it:
{
"job_id": "5f0c2a8e-3b1d-4c7e-9a2f-6d8e1b4c0a37",
"kind": "checkpoint",
"name": "my-checkpoint",
"snapshot_id": "snap_7fJk2mQpXv9dLc3RtY",
"status": "pending",
"vm_id": "{sandboxId}"
}POST /sandboxes/{sandboxId}/snapshots accepts the following field:
| Field | Type | Description |
|---|---|---|
name | string | Sets the checkpoint name. The name has 1 to 128 characters from A-Z, a-z, 0-9, ., _, and -. It must not start with . or prj-, and it must be unique in the project. This field is required. |
POST /sandboxes/gpu/from-snapshot accepts the following fields:
| Field | Type | Description |
|---|---|---|
snapshot | string | Sets the checkpoint to restore, by name or snap_ ID. This field is required. |
name | string | Sets the display name. If omitted, a name is generated. |
labels | object | Attaches key-value metadata to the sandbox. |
lifecycle | object | Sets the lifecycle policy with timeout_secs and on_timeout, and idle_timeout_secs and on_idle_timeout. The only action is delete. |
ports | array | Forwards inbound ports to the sandbox. |
region | string | Sets the region or global region slug. The default is the project default. |
idempotency_key | string | Makes a retried create return the same sandbox. You can also send it as the Idempotency-Key header. |
create_ttl | integer | Sets how many seconds the sandbox has to reach running before it is deleted. The default is 3600, and the maximum is 86400. |
wait | integer | Sets how long the server holds the request for the sandbox to start. By default, the server holds it for at most 3 seconds. |