---
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'
```