Sign Up

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:

DimensionWhat scalesMechanisms
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),
)
ParameterTypeDescription
cpufloatSets 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.
memoryintIn GiB.
diskintIn 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:

MechanismStarting stateUse
Snapshot fan-outMemory and disk from the snapshotAny number of identical environments from one prepared snapshot
ForkFilesystem and memory of a running or paused persistent sandboxBranch 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)
ParameterTypeDescription
waitintSets 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.

ControlWhat it limitsScope
ResourcesMaximum vCPU, memory, and disk of a single sandboxSandbox
CreditsSpending across sandboxes; creates are rejected when the balance is exhaustedOrganization

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, wait long-polls one sandbox, and ids waits on up to 200 sandboxes over one connection, returning once one reaches the target state or timeout_ms elapses.
# 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'