--- title: Scale description: 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**](/docs/v2/sandboxes#resources)
• [**Resource limits**](/docs/v2/limits#sandbox-limits) | | **Fleet**
(horizontal) | Number of sandboxes running simultaneously | • [**Snapshot fan-out**](/docs/v2/snapshots) | | **Workload**
(concurrency) | Concurrent processes in a sandbox | • [**Sessions**](/docs/v2/process-execution#sessions)
• [**Background commands**](/docs/v2/process-execution#start-a-background-process)
• [**PTY sessions**](/docs/v2/pty) | ## 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](/docs/v2/limits#sandbox-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. ```python 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. | - The API raises values below the [minimums](/docs/v2/sandboxes#resources) to those minimums. ```typescript import { Daytona } from '@daytona/sdk' const daytona = new Daytona() // Guarantee 2 vCPUs, 4 GiB of RAM, and 16 GiB of disk for the sandbox const sandbox = await daytona.v2.create({ resources: { cpu: 2, memory: 4, disk: 16 }, }) ``` | **Parameter** | **Type** | **Description** | | ------------- | -------- | ---------------------------------------- | | `cpu` | `number` | 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` | `number` | In GiB. | | `disk` | `number` | In GiB. | - The API raises values below the [minimums](/docs/v2/sandboxes#resources) to those minimums. ```bash # Guarantee 2 vCPUs, 4 GiB of RAM, and 16 GiB of disk; --memory and --disk are MiB daytona sandbox create --cpu 2 --memory 4096 --disk 16384 ``` | **Flag** | **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 4096 MiB of memory. | - The API raises values below the [minimums](/docs/v2/sandboxes#resources) to those minimums. ```bash curl 'https://api.daytona.com/sandboxes' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "cpu": 2, "memory_mib": 4096, "disk_mib": 16384 }' ``` | **Field** | **Type** | **Description** | | ------------- | --------- | ---------------------------- | | `cpu` | `number` | Sets the CPU guarantee in cores. The value can be fractional. The API raises `cpu` to at least 1 core per 4096 MiB of `memory_mib`. | | `memory_mib` | `integer` | In MiB. | | `disk_mib` | `integer` | In MiB. | - The API raises values below the [minimums](/docs/v2/sandboxes#resources) to those minimums. A sandbox bursts beyond its guarantee up to the platform caps: **16** vCPUs and **32** GiB of memory. The per-sandbox vCPU and memory limits lower those ceilings and cannot raise them. CPU guarantees can be fractional, as small as 0.125 cores. Usage above the guarantee is billed as measured; see [billing](/docs/v2/billing). ```python from daytona import Daytona from daytona.v2 import Resources daytona = Daytona() # Guarantee half a core and 2 GiB, and burst up to 4 vCPUs and 8 GiB sandbox = daytona.v2.create( resources=Resources(cpu=0.5, cpu_max=4, memory=2, memory_max=8), ) ``` | **Parameter** | **Type** | **Description** | | ------------- | -------- | --------------------------------------- | | `cpu_max` | `int` | Whole vCPUs from `1` to `16`. | | `memory_max` | `float` | In GiB, from 256 MiB to 32 GiB. | ```typescript import { Daytona } from '@daytona/sdk' const daytona = new Daytona() // Guarantee half a core and 2 GiB, and burst up to 4 vCPUs and 8 GiB const sandbox = await daytona.v2.create({ resources: { cpu: 0.5, cpuMax: 4, memory: 2, memoryMax: 8 }, }) ``` | **Parameter** | **Type** | **Description** | | ------------- | -------- | ------------------------------- | | `cpuMax` | `number` | Whole vCPUs from `1` to `16`. | | `memoryMax` | `number` | In GiB, from 256 MiB to 32 GiB. | ```bash # Guarantee half a core and 2 GiB, and burst up to 4 vCPUs and 8 GiB daytona sandbox create --cpu 0.5 --vcpus-max 4 --memory 2048 --mem-max 8192 ``` | **Flag** | **Type** | **Description** | | ------------- | -------- | ----------------------------------- | | `--vcpus-max` | `int32` | Whole vCPUs from `1` to `16`. | | `--mem-max` | `int32` | In MiB, from `256` to `32768`. | ```bash curl 'https://api.daytona.com/sandboxes' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "cpu": 0.5, "vcpus_max": 4, "memory_mib": 2048, "memory_max_mib": 8192 }' ``` | **Field** | **Type** | **Description** | | ------------- | --------- | ------------------------------ | | `vcpus_max` | `integer` | Whole vCPUs from `1` to `16`. | | `memory_max_mib` | `integer` | In MiB, from `256` to `32768`. | ## 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. [Snapshot fan-out](/docs/v2/snapshots) starts each unit of work from the memory and disk of one prepared snapshot, so any number of identical environments run from the same state. Snapshot fan-out works with Linux sandboxes. macOS sandboxes start from a disk image instead: see [macOS snapshots](/docs/v2/macos-sandboxes#filesystem-snapshot). ```python 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}") # Delete the sandbox 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. | - Each create counts toward the organization's [concurrent sandbox limit](/docs/v2/limits#organization-limits) when one is set. - The SDK does not retry a create that the limit or a saturated admission queue refuses. ```python import asyncio from daytona import AsyncDaytona async def run_task(daytona: AsyncDaytona, shard: int) -> str: # Each task gets its own isolated sandbox from the same snapshot sandbox = await daytona.v2.create_from_snapshot("my-snapshot") response = await sandbox.process.run(f"python3 run.py --shard {shard}") # Delete the sandbox when the task is done await sandbox.delete() return response.stdout async def main() -> None: async with AsyncDaytona() as daytona: # Create and run 20 sandboxes concurrently from the same snapshot results = await asyncio.gather(*(run_task(daytona, i) for i in range(20))) print(results) asyncio.run(main()) ``` | **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. | - Each create counts toward the organization's [concurrent sandbox limit](/docs/v2/limits#organization-limits) when one is set. - The SDK does not retry a create that the limit or a saturated admission queue refuses. ```typescript import { Daytona } from '@daytona/sdk' const daytona = new Daytona() async function runTask(shard: number): Promise { // Each task gets its own isolated sandbox from the same snapshot const sandbox = await daytona.v2.createFromSnapshot('my-snapshot') const response = await sandbox.process.run(`python3 run.py --shard ${shard}`) // Delete the sandbox when the task is done await sandbox.delete() return response.stdout } // Create and run 20 sandboxes concurrently from the same snapshot const results = await Promise.all( Array.from({ length: 20 }, (_, i) => runTask(i)) ) console.log(results) ``` | **Parameter** | **Type** | **Description** | | ------------- | -------- | --------------------------------------------------------------------------------- | | `wait` | `number` | Sets how many seconds `createFromSnapshot` waits for the sandbox to start. The default is `60`. When `wait` runs out, `createFromSnapshot` returns the sandbox without throwing. The returned sandbox may not have started. | - Each create counts toward the organization's [concurrent sandbox limit](/docs/v2/limits#organization-limits) when one is set. - The SDK does not retry a create that the limit or a saturated admission queue refuses. ```bash # Create each sandbox from the same snapshot (run commands concurrently as needed) daytona sandbox create-from-snapshot my-snapshot ``` ```bash # Create each sandbox from the same snapshot (issue requests concurrently as needed) curl 'https://api.daytona.com/sandboxes/from-snapshot' \ --request POST \ --header 'Content-Type: application/json' \ --header 'Authorization: Bearer YOUR_API_KEY' \ --data '{ "snapshot": "my-snapshot" }' ``` ## 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](/docs/v2/preview). 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](/docs/v2/process-execution#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](/docs/v2/pty) add interactive terminals. ```python 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) ``` ```typescript import { Daytona } from '@daytona/sdk' const daytona = new Daytona() const sandbox = await daytona.v2.create() // Start the server as a background process; the handle returns immediately await sandbox.process.start('python3 -m http.server 8000') // Other commands run concurrently in the same sandbox const response = await sandbox.process.run({ argv: ['python3', '-c', "import time, urllib.request as u; time.sleep(1); print(u.urlopen('http://localhost:8000').status)"], }) console.log(response.stdout) ``` ```python from daytona import Daytona daytona = Daytona() sandbox = daytona.v2.create() # start returns a handle immediately while the command runs in the background handle = sandbox.process.start("pip install numpy") # Wait for completion and read the exit code later result = handle.wait() print(result.exit_code) ``` ```typescript import { Daytona } from '@daytona/sdk' const daytona = new Daytona() const sandbox = await daytona.v2.create() // start returns a handle immediately while the command runs in the background const handle = await sandbox.process.start('pip install numpy') // Wait for completion and read the exit code later const result = await handle.wait() console.log(result.exitCode) ``` ## Capacity and throughput Fleet size operates within per-sandbox platform caps and your organization's credit balance. | **Control** | **What it limits** | **Scope** | | --------------------------------------------- | ----------------------------------------------------------------------------- | ------------ | | [**Resources**](/docs/v2/sandboxes#resources) | Maximum vCPU, memory, and disk of a single sandbox | Sandbox | | [**Credits**](/docs/v2/billing) | Spending across sandboxes; creates are rejected when the balance is exhausted | Organization | ### Reclaiming capacity Delete sandboxes when their work is done to release compute and storage: - **Sandboxes** release compute and storage immediately on delete. - **[Spot sandboxes](/docs/v2/preemption#spot-sandboxes)** are deleted automatically when the platform needs capacity. See [preemption](/docs/v2/preemption). ### Operating at scale At high creation rates, two practices keep an application efficient: - Make creates safe to retry with an [idempotency key](/docs/v2/linux-sandboxes#create-a-linux-sandbox): 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 the batch wait endpoint waits on up to `200` sandboxes over one connection, returning once one reaches the target state or `timeout_ms` elapses. ```bash # 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/batch-wait?ids={sandboxId1},{sandboxId2},{sandboxId3}&wait=running&timeout_ms=60000' \ --header 'Authorization: Bearer YOUR_API_KEY' ```