Scale
Sandbox scalability and concurrency.
Daytona sandboxes are designed to be created and operated at high volume. A single sandbox scales up by bursting beyond its guaranteed resources, a fleet scales out by running many sandboxes at once, and each sandbox runs multiple processes concurrently.
Scale operates along three dimensions:
| Dimension | What scales | Mechanisms |
|---|---|---|
| Sandbox (vertical) | vCPU, RAM, and disk of a single sandbox | • Custom resources • Resource limits |
| Fleet (horizontal) | Number of sandboxes running simultaneously | • Snapshot fan-out • Fork |
| Workload (concurrency) | Concurrent processes in a sandbox | • Sessions • Background commands • PTY sessions |
Sandbox scaling
Sandbox scaling sets the resources of a single sandbox: vCPU, memory, and disk. The resource envelope is fixed when the sandbox is created; there is no resize operation.
The requested resources are a guaranteed floor, reserved at placement; beyond it the sandbox uses idle host capacity up to its resource limits, which default to the platform caps.
Size the guarantee for the workload's average, and let bursting absorb the peaks. For a fixed shape with no bursting, set every limit equal to its request.
Guarantee CPU, memory, and disk when creating a sandbox.
from daytona import Daytona
from daytona.v2 import Resources
daytona = Daytona()
# Guarantee 2 vCPUs, 4 GiB of RAM, and 16 GiB of disk for the sandbox
sandbox = daytona.v2.create(
resources=Resources(cpu=2, memory=4, disk=16),
)| Parameter | Type | Description |
|---|---|---|
cpu | float | Sets the CPU guarantee in cores. The value can be fractional. The API raises the CPU guarantee to at least 1 core per 4 GiB of memory. |
memory | int | In GiB. |
disk | int | In GiB. |
Fleet scaling
Fleet scaling raises how many sandboxes run at once. The unit of scale is the sandbox: instead of packing unrelated workloads into one environment, create one per user, task, or agent.
Each sandbox is a hardware-isolated microVM, so a fleet scales linearly: each sandbox adds capacity without contention, and a failure in one does not affect others. Creation is fast and asynchronous, so scale on demand: create when work arrives, delete when done.
The mechanisms differ in what state each unit of work starts with:
| Mechanism | Starting state | Use |
|---|---|---|
| Snapshot fan-out | Memory and disk from the snapshot | Any number of identical environments from one prepared snapshot |
| Fork | Filesystem and memory of a running or paused persistent sandbox | Branch a live environment into independent copies |
from concurrent.futures import ThreadPoolExecutor
from daytona import Daytona
daytona = Daytona()
def run_task(shard: int) -> str:
# Each task gets its own isolated sandbox from the same snapshot
sandbox = daytona.v2.create_from_snapshot("my-snapshot")
response = sandbox.process.run(f"python3 run.py --shard {shard}")
# Sandboxes are ephemeral by default; delete when the task is done
sandbox.delete()
return response.stdout
# Create and run 20 sandboxes concurrently from the same snapshot
with ThreadPoolExecutor(max_workers=20) as pool:
results = list(pool.map(run_task, range(20)))
print(results)| Parameter | Type | Description |
|---|---|---|
wait | int | Sets how many seconds create_from_snapshot waits for the sandbox to start. The default is 60. When wait runs out, create_from_snapshot returns the sandbox without raising. The returned sandbox may not have started. |
Workload concurrency
Workload concurrency runs multiple processes inside a single sandbox. A single sandbox can run an API server, a database, and background workers side by side: all processes share the sandbox's filesystem and network, and exposed ports are reachable through previews.
Every command runs as a process: run starts a process and waits for it, while start returns a handle immediately and the process continues in the background. Sessions are shared shells: commands in a session run sequentially and share state, so parallelism comes from separate sessions or background processes. Pseudo terminal (PTY) sessions add interactive terminals.
from daytona import Daytona
daytona = Daytona()
sandbox = daytona.v2.create()
# Start the server as a background process; the handle returns immediately
sandbox.process.start("python3 -m http.server 8000")
# Other commands run concurrently in the same sandbox
response = sandbox.process.run(argv=[
"python3", "-c",
"import time, urllib.request as u; time.sleep(1); print(u.urlopen('http://localhost:8000').status)",
])
print(response.stdout)Capacity and throughput
Fleet size operates within per-sandbox platform caps and your organization's credit balance.
| Control | What it limits | Scope |
|---|---|---|
| Resources | Maximum vCPU, memory, and disk of a single sandbox | Sandbox |
| Credits | Spending across sandboxes; creates are rejected when the balance is exhausted | Organization |
Reclaiming capacity
Only running sandboxes use compute, so a fleet can far exceed its running subset:
- Ephemeral sandboxes, the default, release compute and storage immediately on delete.
- Persistent sandboxes release compute without losing state: stop keeps the filesystem, pause also keeps memory and processes, and either state bills for storage only.
- Spot sandboxes are reclaimed automatically when the platform needs capacity: a persistent spot sandbox is paused and can be resumed later; an ephemeral one is deleted. See preemption.
Operating at scale
At high creation rates, two practices keep an application efficient:
- Make creates safe to retry with an idempotency key: a retried create with the same key returns the same sandbox instead of minting a new one.
- Wait with long-polls, not tight polling. The SDKs block on create until the sandbox runs. On the API,
waitlong-polls one sandbox, andidswaits on up to200sandboxes over one connection, returning once one reaches the target state ortimeout_mselapses.
# Wait for one sandbox to reach running without tight polling
curl 'https://api.daytona.com/sandboxes/{sandboxId}?wait=running' \
--header 'Authorization: Bearer YOUR_API_KEY'
# Wait on a whole batch over one connection (up to 200 IDs)
curl 'https://api.daytona.com/sandboxes?ids={sandboxId1},{sandboxId2},{sandboxId3}&wait=running&timeout_ms=60000' \
--header 'Authorization: Bearer YOUR_API_KEY'