# Scale (/docs/scale)

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.

<ScaleVisual />

Scale operates along three dimensions:

| **Dimension**          | **What scales**                              | **Mechanisms**                                                                                                                                                                                        |
| ---------------------- | -------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Sandbox** <br /> (vertical)     | vCPU, RAM, and disk of a single sandbox      | • [**Custom resources**](/docs/sandboxes#resources) <br /> • [**Resource limits**](/docs/limits#sandbox-limits)                                                                          |
| **Fleet** <br /> (horizontal)     | Number of sandboxes running simultaneously | • [**Snapshot fan-out**](/docs/snapshots)                                                                                                             |
| **Workload** <br /> (concurrency) | Concurrent processes in a sandbox | • [**Sessions**](/docs/process-execution#session-operations) <br /> • [**Background commands**](/docs/process-execution#start-a-background-process) <br /> • [**PTY sessions**](/docs/pty) |

## Sandbox scaling [#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/limits#sandbox-limits), which default to the [plan caps](/docs/limits#sandbox-limits) of your organization.

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.

<Tabs syncKey="vertical-workflow">
<TabItem label="Custom resources">

Guarantee CPU, memory, and disk when creating a sandbox.

<Tabs syncKey="language">
<TabItem label="Python" icon="seti:python">

```python
from daytona import Daytona
from daytona.v2 import Resources

daytona = Daytona()

# Guarantee 2 cores, 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 API raises the CPU guarantee to at least 1 core per 8 GiB of memory. The value can be fractional. |
| `memory`      | int    | Sets the memory guarantee in GiB.                                  |
| `disk`        | int    | Sets the disk guarantee in GiB.                                  |

</TabItem>
<TabItem label="TypeScript" icon="seti:typescript">

```typescript
import { Daytona } from '@daytona/sdk'

const daytona = new Daytona()

// Guarantee 2 cores, 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 API raises the CPU guarantee to at least 1 core per 8 GiB of memory. The value can be fractional. |
| `memory`      | number | Sets the memory guarantee in GiB.                                  |
| `disk`        | number | Sets the disk guarantee in GiB.                                  |

</TabItem>
<TabItem label="CLI" icon="seti:shell">

```bash
# Guarantee 2 cores, 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 API raises the CPU guarantee to at least 1 core per 8192 MiB of memory. The value can be fractional. |

</TabItem>
<TabItem label="API" icon="seti:json">

```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 8192 MiB of `memory_mib`. |
| `memory_mib`     | integer | In MiB.                      |
| `disk_mib` | integer | In MiB.                      |

</TabItem>
</Tabs>

</TabItem>
<TabItem label="Burst ceilings">

A sandbox bursts beyond its guarantee up to the [plan caps](/docs/limits#sandbox-limits) of your organization: **4** cores (8 vCPUs) and **16** GiB of memory on Starter, **8** cores (16 vCPUs) and **32** GiB on Team, and the platform caps of **16** cores (32 vCPUs) and **32** GiB on Enterprise. The ranges below are the platform caps; a value above the plan cap is rejected. The per-sandbox core 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/billing).

<Tabs syncKey="language">
<TabItem label="Python" icon="seti:python">

```python
from daytona import Daytona
from daytona.v2 import Resources

daytona = Daytona()

# Guarantee half a core and 2 GiB, and burst up to 2 cores (4 vCPUs) and 8 GiB
sandbox = daytona.v2.create(
    resources=Resources(cpu=0.5, cpu_max=2, memory=2, memory_max=8),
)
```

| **Parameter** | **Type** | **Description**                         |
| ------------- | -------- | --------------------------------------- |
| `cpu_max`     | float  | Sets the CPU limit in cores, a multiple of `0.5`, up to the plan cap. One core is 2 vCPUs. |
| `memory_max`  | float  | Sets the memory limit in GiB, from 256 MiB to 32 GiB.         |

</TabItem>
<TabItem label="TypeScript" icon="seti:typescript">

```typescript
import { Daytona } from '@daytona/sdk'

const daytona = new Daytona()

// Guarantee half a core and 2 GiB, and burst up to 2 cores (4 vCPUs) and 8 GiB
const sandbox = await daytona.v2.create({
  resources: { cpu: 0.5, cpuMax: 2, memory: 2, memoryMax: 8 },
})
```

| **Parameter** | **Type** | **Description**                 |
| ------------- | -------- | ------------------------------- |
| `cpuMax`      | number | Sets the CPU limit in cores, a multiple of `0.5`, up to the plan cap. One core is 2 vCPUs. |
| `memoryMax`   | number | Sets the memory limit in GiB, from 256 MiB to 32 GiB. |

</TabItem>
<TabItem label="CLI" icon="seti:shell">

```bash
# Guarantee half a core and 2 GiB, and burst up to 2 cores (4 vCPUs) and 8 GiB
daytona sandbox create --cpu 0.5 --cpu-max 2 --memory 2048 --memory-max 8192
```

| **Flag**       | **Type** | **Description**                     |
| -------------- | -------- | ----------------------------------- |
| `--cpu-max`    | float  | Cores, a multiple of 0.5, up to the plan cap. One core is 2 vCPUs. |
| `--memory-max` | int32  | In MiB, from `256` to `32768`.      |

</TabItem>
<TabItem label="API" icon="seti:json">

```bash
curl 'https://api.daytona.com/sandboxes' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "cpu": 0.5,
  "cores_max": 2,
  "memory_mib": 2048,
  "memory_max_mib": 8192
}'
```

| **Field**     | **Type**  | **Description**                |
| ------------- | --------- | ------------------------------ |
| `cores_max`   | number  | Cores, a multiple of 0.5, up to the plan cap. One core is 2 vCPUs. |
| `memory_max_mib` | integer | In MiB, from `256` to `32768`. |

</TabItem>
</Tabs>

</TabItem>
</Tabs>

## Fleet scaling [#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/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/macos-sandboxes#filesystem-snapshot).

<Tabs syncKey="language">
<TabItem label="Python" icon="seti:python">

```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. When `wait` runs out, `create_from_snapshot` returns the sandbox without raising. The returned sandbox may not have started. The default is `60`. |

</TabItem>
<TabItem label="Python (async)" icon="seti:python">

```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. When `wait` runs out, `create_from_snapshot` returns the sandbox without raising. The returned sandbox may not have started. The default is `60`. |

</TabItem>
<TabItem label="TypeScript" icon="seti:typescript">

```typescript
import { Daytona } from '@daytona/sdk'

const daytona = new Daytona()

async function runTask(shard: number): Promise<string> {
  // 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. When `wait` runs out, `createFromSnapshot` returns the sandbox without throwing. The returned sandbox may not have started. The default is `60`. |

</TabItem>
<TabItem label="CLI" icon="seti:shell">

```bash
# Create each sandbox from the same snapshot (run commands concurrently as needed)
daytona sandbox create-from-snapshot my-snapshot
```

</TabItem>
<TabItem label="API" icon="seti:json">

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

</TabItem>
</Tabs>

## Workload concurrency [#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/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/process-execution#session-operations) 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/pty) add interactive terminals.

<Tabs syncKey="concurrency-workflow">
<TabItem label="Concurrent processes">

<Tabs syncKey="language">
<TabItem label="Python" icon="seti:python">

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

</TabItem>
<TabItem label="TypeScript" icon="seti:typescript">

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

</TabItem>
</Tabs>

</TabItem>
<TabItem label="Background commands">

<Tabs syncKey="language">
<TabItem label="Python" icon="seti:python">

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

</TabItem>
<TabItem label="TypeScript" icon="seti:typescript">

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

</TabItem>
</Tabs>

</TabItem>
</Tabs>

## Capacity and throughput [#capacity-and-throughput]

Fleet size operates within per-sandbox platform and plan caps and your organization's credit balance.

| **Control**                                   | **What it limits**                                                            | **Scope**    |
| --------------------------------------------- | ----------------------------------------------------------------------------- | ------------ |
| [**Resources**](/docs/sandboxes#resources) | Maximum vCPU, memory, and disk of a single sandbox                            | Sandbox      |
| [**Credits**](/docs/billing)               | Spending across sandboxes; creates are rejected when the balance is exhausted | Organization |

### Reclaiming capacity [#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/preemption#spot-sandboxes)** are reclaimed automatically when the platform needs capacity. See [preemption](/docs/preemption).

### Operating at scale [#operating-at-scale]

At high creation rates, two practices keep an application efficient:

- Make creates safe to retry with an [idempotency key](/docs/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'
```
