# Linux Sandboxes (/docs/linux-sandboxes)

Linux sandboxes are **Linux virtual machines (VMs)**. Each sandbox is a virtual machine, a microVM, that runs its own Linux kernel on shared physical hardware and has its own operating system, files, network connection, and fixed amount of processor, memory, and disk. The hardware enforces the boundary and isolation between sandboxes. 

<LinuxSandboxesVisual />

| **Term**       | **Description**                                                                                                |
| -------------- | -------------------------------------------------------------------------------------------------------------- |
| **Sandbox**    | An isolated Linux machine created on demand to run code.                                                       |
| **Host**       | The physical server that runs many sandboxes at once. Daytona calls these servers runners.                     |
| **Guest**      | The operating system running inside a sandbox, as opposed to the operating system of the host.                 |
| **Kernel**     | The core of an operating system. It manages memory, processes, files, and devices.                             |
| **Hypervisor** | Software on the host that creates virtual machines and keeps them separated from each other and from the host. |
| **Image**      | A packaged filesystem that defines what software a sandbox starts with.           |
| **Snapshot**   | A saved copy of a sandbox's memory and disk that new sandboxes resume from.                                    |
| **Spot**       | A sandbox that runs on discounted capacity that Daytona can reclaim at any time.                               |

## Use cases [#use-cases]

Sandboxes are used wherever code must run in a real environment, but you cannot trust the code or you cannot afford for it to affect anything else.

- **Code execution for AI agents.** An agent writes code, runs it in a sandbox, reads the output, and decides what to do next. The sandbox gives the agent a real shell and filesystem while keeping its actions away from your infrastructure. Once the agent is done, a [delete](#delete) discards the sandbox's filesystem and memory.

- **Coding agents.** An agent clones a repository, installs dependencies, edits files, runs the test suite, and opens a pull request, all inside one sandbox. The sandbox keeps its filesystem on its host until it is deleted. A [filesystem snapshot](#filesystem-snapshot) saves that filesystem as an image, and new sandboxes boot from it with the captured files.

- **Reinforcement learning (RL).** Training runs create very large numbers of identical environments, run one episode in each, score the result, and discard the environment. Fast creation from a shared snapshot keeps the cost of each environment low. A restored sandbox resumes the captured processes and memory instead of booting.

- **Untrusted user code.** Online coding platforms, grading systems, and plugin hosts run code submitted by users without exposing other users or the service. Each sandbox is a microVM with its own Linux kernel. The hardware enforces the boundary between sandboxes.

- **Development environments.** A developer gets a preconfigured machine from an image, connects over SSH or from an editor, and previews web applications through a URL. Requests through SSH, VNC, and preview URLs count as activity for the idle timeout. A [reset of the idle timer](#reset-the-idle-timer) keeps the sandbox alive during work that Daytona does not count as activity.

## Create a Linux sandbox [#create-a-linux-sandbox]

Create a Linux sandbox from the dashboard or programmatically.

1. Go to [Daytona Sandboxes ↗](https://app.daytona.com/dashboard/sandboxes)
2. Click <Button>Create</Button>
3. Select <Button>Linux sandbox</Button>
4. Click <Button>Create</Button>

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create()
```

The following example sets the remaining parameters:

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

daytona = Daytona()

sandbox = daytona.v2.create(
    name="my-sandbox",
    labels={"team": "research", "run": "42"},
    resources=Resources(cpu=2, memory=4, disk=20),
    ports=[PortMapping(port=8080), PortMapping(port=5353, proto="udp")],
    network_policy={"block_all": True, "allow_domains": ["pypi.org", "*.github.com"]},
    env={"LOG_LEVEL": "debug"},
    secrets=["GITHUB_TOKEN"],
    spot=False,
    cpu_arch="amd64",
    cpu_type="zen5",
    lifecycle_policy={
        "idle_expiry_seconds": 3600,
        "on_idle_timeout": "delete",
        "timeout_seconds": 604800,
        "on_timeout": "delete",
    },
    idempotency_key="run-42-create",
    wait_seconds=120,
)
```

| **Parameter**     | **Type**                | **Description**                                                                                                                                                                                                                  |
| ----------------- | ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `image` | str | Sets the registered image that the sandbox starts from, by name or `img_` ID. This is the first positional argument. If omitted, the sandbox boots the platform default image, the platform image whose `default` field is `true` in the [image list](/docs/images#list-images). When no default image is set, the request returns a 400 error. |
| `name` | str | Sets the display name. If omitted, a name is generated. Within one [workload cell](/docs/regions), a create with the same name and different arguments is refused until the first sandbox is deleted. The name is also stored as the `name` label. |
| `labels` | Dict\[str, str\] | Attaches key-value metadata to the sandbox. |
| `user` | str | Sets the default OS user inside the sandbox. The default is the image's `USER`, or `root` if the image sets none, sets root, or sets a numeric user ID. |
| `resources` | Resources | Sets the sandbox size. `cpu` sets the guaranteed CPU cores as a float, raised to at least 0.125; the value is raised to at least one core per 8 GiB of guaranteed memory, and if omitted it is one core per 8 GiB of guaranteed memory, and at least 0.5: 0.5 with the default 1 GiB. `memory` sets the guaranteed memory in GiB, raised to at least 0.5 GiB, default 1 GiB. `disk` sets the guaranteed writable disk in GiB, default 512 MiB. When `cpu`, `memory`, or `disk` is set, the disk is raised to at least 10 GiB. `cpu_max` sets the CPU limit in cores as a multiple of 0.5, which defaults to the system or plan cap. `memory_max` sets the memory limit in GiB, from 0.25 to 32, which defaults to 32. If `memory` is omitted, the guaranteed memory is lowered to the limit. If `memory` is set, a guaranteed memory above the limit, after the raise to 0.5 GiB, is refused. `disk_max` sets the writable disk limit in GiB. Memory and disk must convert to a whole number of MiB. |
| `ports` | Sequence\[PortMapping\] | Forwards inbound ports to the sandbox. Each mapping has a `port` and a `proto`, which defaults to `tcp`. |
| `volumes` | Sequence\[VolumeMount\] | Attaches volumes to the sandbox. See [attach volumes](/docs/volumes#attach-volumes). |
| `env` | Dict\[str, str\] | Sets environment variables inside the sandbox. |
| `secrets` | Sequence\[str\] | Attaches project secrets by name. The sandbox sees each secret as an opaque placeholder. A name that is not a secret of the project is refused. |
| `network_policy` | NetworkPolicyInput | Sets the outbound network policy with `block_all`, `allow_domains`, and `allow_cidrs`. `allow_domains` implies `block_all`. `allow_cidrs` restricts egress only together with `block_all` or `allow_domains`. A `*.` wildcard domain matches subdomains only, so list the parent domain separately. A create with a policy is refused when no runner in the region can enforce it for the sandbox's CPU architecture and type. You can [change it](/docs/network-limits#update-network-policy) after create. |
| `spot` | bool | Runs the sandbox on discounted capacity that can be reclaimed. The default is `False`. |
| `region` | str | Sets the region, any listed region including `earth`. The default is the project's default region, then the organization's, then `earth`. A create in a region with no online Linux runner is refused. |
| `cpu_arch` | str | Sets the CPU architecture, `amd64` or `arm64`. The default is the region's default architecture, or `amd64` if the region sets none. A create with an architecture that no runner in the region provides is refused, or waits until its create deadline. |
| `cpu_type` | str | Sets the CPU hardware tier slug: `zen3`, `zen4`, `zen5`, `zen5c`, `arrowlake1`, `arrowlake2`, `graviton`, `graviton3`, and `graviton4`. The slug also sets the architecture. A create with a type that no runner in the region serves, itself or as a fallback, is refused, or waits until its create deadline. See [CPU types](#cpu-types). |
| `lifecycle_policy` | LifecyclePolicyOptions | Sets the lifecycle policy with `timeout_seconds` and `on_timeout`, and `idle_expiry_seconds` and `on_idle_timeout`. The action is `delete`. By default, there is no idle timeout unless the project sets one, and the wall-clock timeout uses the project or platform default, if one is enabled. |
| `idempotency_key` | str | Makes a retried create in the same workload cell return the same sandbox. A create in another cell makes a separate sandbox. To keep creates in one region, set `region`. If `name` is set, the key is derived from it. Otherwise, each call generates a new key. |
| `create_timeout_seconds` | int | Sets how many seconds the sandbox has to reach running before it is deleted. `-1` sets the maximum, 86400. The default is the server default, 3600. |
| `wait_seconds` | int | Sets how many seconds create waits for the sandbox to start. The server holds the request for up to 3 seconds, and the SDK waits for the rest. `0` returns immediately. The default is 60. If the sandbox has not started in time, or fails, `create()` returns it without raising. Check `sandbox.state` before using it. |

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create()
```

The following example sets the remaining parameters:

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

const daytona = new Daytona()

const sandbox = await daytona.v2.create({
  name: 'my-sandbox',
  labels: { team: 'research', run: '42' },
  resources: { cpu: 2, memory: 4, disk: 20 },
  ports: [{ port: 8080 }, { port: 5353, proto: 'udp' }],
  networkPolicy: { blockAll: true, allowDomains: ['pypi.org', '*.github.com'] },
  env: { LOG_LEVEL: 'debug' },
  secrets: ['GITHUB_TOKEN'],
  spot: false,
  cpuArch: 'amd64',
  cpuType: 'zen5',
  lifecyclePolicy: {
    idleExpirySeconds: 3600,
    onIdleTimeout: 'delete',
    timeoutSeconds: 604800,
    onTimeout: 'delete',
  },
  idempotencyKey: 'run-42-create',
  waitSeconds: 120,
})
```

| **Parameter**    | **Type**                | **Description**                                                                                                                                                                                                     |
| ---------------- | ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `image` | string | Sets the registered image that the sandbox starts from, by name or `img_` ID. This is the first positional argument. If omitted, the sandbox boots the platform default image, the platform image whose `default` field is `true` in the [image list](/docs/images#list-images). When no default image is set, the request returns a 400 error. |
| `name` | string | Sets the display name. If omitted, a name is generated. Within one [workload cell](/docs/regions), a create with the same name and different arguments is refused until the first sandbox is deleted. The name is also stored as the `name` label. |
| `labels` | Record\<string, string> | Attaches key-value metadata to the sandbox. |
| `user` | string | Sets the default OS user inside the sandbox. The default is the image's `USER`, or `root` if the image sets none, sets root, or sets a numeric user ID. |
| `resources` | Resources | Sets the sandbox size. `cpu` sets the guaranteed CPU cores as a float, raised to at least 0.125; the value is raised to at least one core per 8 GiB of guaranteed memory, and if omitted it is one core per 8 GiB of guaranteed memory, and at least 0.5: 0.5 with the default 1 GiB. `memory` sets the guaranteed memory in GiB, raised to at least 0.5 GiB, default 1 GiB. `disk` sets the guaranteed writable disk in GiB, default 512 MiB. When `cpu`, `memory`, or `disk` is set, the disk is raised to at least 10 GiB. `cpuMax` sets the CPU limit in cores as a multiple of 0.5, which defaults to the system or plan cap. `memoryMax` sets the memory limit in GiB, from 0.25 to 32, which defaults to 32. If `memory` is omitted, the guaranteed memory is lowered to the limit. If `memory` is set, a guaranteed memory above the limit, after the raise to 0.5 GiB, is refused. `diskMax` sets the writable disk limit in GiB. Memory and disk must convert to a whole number of MiB. |
| `ports` | PortMapping\[\] | Forwards inbound ports to the sandbox. Each mapping has a `port` and a `proto`, which defaults to `tcp`. |
| `volumes` | VolumeMount\[\] | Attaches volumes to the sandbox. See [attach volumes](/docs/volumes#attach-volumes). |
| `env` | Record\<string, string> | Sets environment variables inside the sandbox. |
| `secrets` | string\[\] | Attaches project secrets by name. The sandbox sees each secret as an opaque placeholder. A name that is not a secret of the project is refused. |
| `networkPolicy` | NetworkPolicyInput | Sets the outbound network policy with `blockAll`, `allowDomains`, and `allowCidrs`. `allowDomains` implies `blockAll`. `allowCidrs` restricts egress only together with `blockAll` or `allowDomains`. A `*.` wildcard domain matches subdomains only, so list the parent domain separately. A create with a policy is refused when no runner in the region can enforce it for the sandbox's CPU architecture and type. You can [change it](/docs/network-limits#update-network-policy) after create. |
| `spot` | boolean | Runs the sandbox on discounted capacity that can be reclaimed. The default is `false`. |
| `region` | string | Sets the region, any listed region including `earth`. The default is the project's default region, then the organization's, then `earth`. A create in a region with no online Linux runner is refused. |
| `cpuArch` | CpuArch | Sets the CPU architecture, `amd64` or `arm64`. The default is the region's default architecture, or `amd64` if the region sets none. A create with an architecture that no runner in the region provides is refused, or waits until its create deadline. |
| `cpuType` | string | Sets the CPU hardware tier slug: `zen3`, `zen4`, `zen5`, `zen5c`, `arrowlake1`, `arrowlake2`, `graviton`, `graviton3`, and `graviton4`. The slug also sets the architecture. A create with a type that no runner in the region serves, itself or as a fallback, is refused, or waits until its create deadline. See [CPU types](#cpu-types). |
| `lifecyclePolicy` | LifecyclePolicyOptions | Sets the lifecycle policy with `timeoutSeconds` and `onTimeout`, and `idleExpirySeconds` and `onIdleTimeout`. The action is `delete`. By default, there is no idle timeout unless the project sets one, and the wall-clock timeout uses the project or platform default, if one is enabled. |
| `idempotencyKey` | string | Makes a retried create in the same workload cell return the same sandbox. A create in another cell makes a separate sandbox. To keep creates in one region, set `region`. If `name` is set, the key is derived from it. Otherwise, each call generates a new key. |
| `createTimeoutSeconds` | number | Sets how many seconds the sandbox has to reach running before it is deleted. `-1` sets the maximum, 86400. The default is the server default, 3600. |
| `waitSeconds` | number | Sets how many seconds create waits for the sandbox to start. The server holds the request for up to 3 seconds, and the SDK waits for the rest. `0` returns immediately. The default is 60. If the sandbox has not started in time, or fails, `create()` resolves with it without throwing. Check `sandbox.state` before using it. |

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

```bash
daytona sandbox create
```

The following example sets the remaining flags:

```bash
daytona sandbox create \
  --name my-sandbox \
  --label team=research --label run=42 \
  --user root \
  --cpu 2 --memory 4096 --disk 20480 \
  --cpu-max 4 --memory-max 16384 \
  --port 8080 --port 5353/udp \
  --block-all --allow-domain pypi.org --allow-domain '*.github.com' \
  --env LOG_LEVEL=debug \
  --secret GITHUB_TOKEN \
  --cpu-arch amd64 --cpu-type zen5 \
  --idle-timeout 1h --on-idle-timeout delete \
  --lifecycle-timeout 168h --on-lifecycle-timeout delete \
  --idempotency-key run-42-create
```

| **Flag**            | **Type**                             | **Description**                                                                                                                                    |
| ------------------- | ------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| `--image` | string | Sets the registered image that the sandbox starts from, by name or `img_` ID. If omitted, the sandbox boots the platform default image, the platform image whose `default` field is `true` in the [image list](/docs/images#list-images). When no default image is set, the request returns a 400 error. |
| `--name` | string | Sets the display name. If omitted, a name is generated. |
| `--label` | KEY=VALUE | Attaches a `KEY=VALUE` metadata label. Repeat the flag for more labels. |
| `--user` | string | Sets the default OS user inside the sandbox. The default is the image's `USER`, or `root` if the image sets none, sets root, or sets a numeric user ID. |
| `--cpu` | float | Sets the guaranteed CPU cores as a float, raised to at least 0.125. The value is raised to at least one core per 8 GiB of guaranteed memory. If omitted, the value is one core per 8 GiB of guaranteed memory, and at least 0.5: 0.5 with the default 1024 MiB. |
| `--memory` | int32 | Sets the guaranteed memory in MiB, raised to at least 512. The default is 1024. |
| `--disk` | int32 | Sets the guaranteed writable disk in MiB. The default is 512. When `--cpu`, `--memory`, or `--disk` is set, the disk is raised to at least 10240. |
| `--cpu-max` | float | Sets the CPU limit of the sandbox in cores, a multiple of 0.5. One core is 2 vCPUs. The sandbox boots at this size. The default is the system or plan cap. |
| `--memory-max` | int32 | Sets the memory limit of the sandbox in MiB, from 256 to 32768. If `--memory` is omitted, the guaranteed memory is lowered to the limit. If `--memory` is set, a guaranteed memory above the limit, after the raise to 512, is refused. The default is 32768. |
| `--disk-max` | int32 | Sets the writable disk limit of the sandbox in MiB, from 512 to 262144. |
| `--port` | PORT\[/PROTO\] | Forwards an inbound port, with an optional protocol. Repeat the flag for more ports. |
| `--volume` | VOLUME:MOUNT_PATH\[:SUBPATH\]\[:ro\] | Attaches a volume. Repeat the flag for more volumes. See [attach volumes](/docs/volumes#attach-volumes). |
| `--env` | KEY=VALUE | Sets an environment variable inside the sandbox. Repeat the flag for more variables. |
| `--secret` | string | Attaches a project secret by name. The sandbox sees it as an opaque placeholder. A name that is not a secret of the project is refused. Repeat the flag for more secrets. |
| `--block-all` | bool | Denies all egress that is not explicitly allowed. A create with a network policy is refused when no runner in the region can enforce it for the sandbox's CPU architecture and type. You can [change the policy](/docs/network-limits#update-network-policy) after create through the SDKs or the API. The default is `false`. |
| `--allow-domain` | string | Allows egress to a hostname or a `*.` wildcard domain. A wildcard matches subdomains only, so list the parent domain separately. It implies `--block-all`. Repeat the flag for more domains. |
| `--allow-cidr` | string | Allows egress to an IPv4 address or CIDR block, on any port. It needs `--block-all` or `--allow-domain`. Repeat the flag for more addresses. |
| `--spot` | bool | Runs the sandbox on discounted capacity that can be reclaimed. The default is `false`. |
| `--region` | string | Sets the region, any listed region including `earth`. The default is the project's default region, then the organization's, then `earth`. A create in a region with no online Linux runner is refused. |
| `--cpu-arch` | string | Sets the CPU architecture, `amd64` or `arm64`. The default is the region's default architecture, or `amd64` if the region sets none. A create with an architecture that no runner in the region provides is refused, or waits until its create deadline. |
| `--cpu-type` | string | Sets the CPU hardware tier slug: `zen3`, `zen4`, `zen5`, `zen5c`, `arrowlake1`, `arrowlake2`, `graviton`, `graviton3`, and `graviton4`. The slug also sets the architecture. A create with a type that no runner in the region serves, itself or as a fallback, is refused, or waits until its create deadline. See [CPU types](#cpu-types). |
| `--lifecycle-timeout` | duration | Sets the wall-clock lifetime as a Go duration such as `2h`, until `--on-lifecycle-timeout` fires. The default is the project or platform default, if one is enabled. |
| `--on-lifecycle-timeout` | string | Sets the action when `--lifecycle-timeout` elapses, `delete`. The default is `delete`. |
| `--idle-timeout` | duration | Sets the idle time as a Go duration, at least `1m`, until `--on-idle-timeout` fires. By default, there is no idle timeout unless the project sets one. |
| `--on-idle-timeout` | string | Sets the action when `--idle-timeout` elapses, `delete`. It is required with `--idle-timeout`. |
| `--idempotency-key` | string | Makes a retried create return the same sandbox. |
| `--server-wait` | duration | Sets how long the server holds the create response for the sandbox to start, as a Go duration. `0s` answers at once. The server default is `3s`. The command then waits until the sandbox is running and prints it, unless `--no-wait` is set. |
| `--timeout` | duration | Sets how long the command waits for the sandbox to start, as a Go duration. The default is `10m`. The sandbox keeps starting after the command stops waiting. |
| `--no-wait` | bool | Prints the create response immediately instead of waiting for the sandbox to start. |
| `--create-ttl` | duration | Sets how long the sandbox has to reach running before the server deletes it, as a Go duration. `max` sets the server maximum, 24 hours. The default is `1h`. |
| `-f`, `--file` | string | Reads the JSON request body from a file, or from standard input with `-`. Flags set on the command line override its fields. |

</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 '{}'
```

The following example sets the remaining fields:

```bash
curl 'https://api.daytona.com/sandboxes' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "name": "my-sandbox",
  "labels": { "team": "research", "run": "42" },
  "user": "root",
  "cpu": 2,
  "memory_mib": 4096,
  "disk_mib": 20480,
  "cores_max": 4,
  "memory_max_mib": 16384,
  "ports": [{ "port": 8080 }, { "port": 5353, "proto": "udp" }],
  "network_policy": { "block_all": true, "allow_domains": ["pypi.org", "*.github.com"] },
  "env": { "LOG_LEVEL": "debug" },
  "secrets": ["GITHUB_TOKEN"],
  "spot": false,
  "cpu_arch": "amd64",
  "cpu_type": "zen5",
  "lifecycle_policy": {
    "idle_expiry_seconds": 3600,
    "on_idle_timeout": "delete",
    "timeout_seconds": 604800,
    "on_timeout": "delete"
  },
  "idempotency_key": "run-42-create"
}'
```

| **Field**         | **Type**         | **Description**                                                                                                                                                                |
| ----------------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `image` | string | Sets the registered image that the sandbox starts from, by name or `img_` ID. If omitted, the sandbox boots the platform default image, the platform image whose `default` field is `true` in the [image list](/docs/images#list-images). When no default image is set, the request returns a 400 error. |
| `name` | string | Sets the display name. If omitted, a name is generated. Names need not be unique. To make a retried create return the same sandbox, send `idempotency_key`. |
| `labels` | object | Attaches key-value metadata to the sandbox. |
| `user` | string | Sets the default OS user inside the sandbox. The default is the image's `USER`, or `root` if the image sets none, sets root, or sets a numeric user ID. |
| `cpu` | number | Sets the guaranteed CPU cores as a float, raised to at least 0.125. The value is raised to at least one core per 8 GiB of guaranteed memory. If omitted, the value is one core per 8 GiB of guaranteed memory, and at least 0.5: 0.5 with the default 1024 MiB. |
| `memory_mib` | integer | Sets the guaranteed memory in MiB, raised to at least 512. The default is 1024. |
| `disk_mib` | integer | Sets the guaranteed writable disk in MiB. The default is 512. When `cpu`, `memory_mib`, or `disk_mib` is set, the disk is raised to at least 10240. |
| `cores_max` | number | Sets the CPU limit of the sandbox in cores, a positive multiple of 0.5. One core is 2 vCPUs. The sandbox boots at this size. The default is the system or plan cap. |
| `memory_max_mib` | integer | Sets the memory limit of the sandbox in MiB, from 256 to 32768. If `memory_mib` is omitted, the guaranteed memory is lowered to the limit. If `memory_mib` is set, a guaranteed memory above the limit, after the raise to 512, is refused. The default is 32768. |
| `disk_max_mib` | integer | Sets the writable disk limit of the sandbox in MiB, from 512 to 262144. |
| `ports` | array | Forwards inbound ports to the sandbox. Each entry has a `port` and a `proto`, which defaults to `tcp`. |
| `volumes` | array | Attaches volumes to the sandbox. See [attach volumes](/docs/volumes#attach-volumes). |
| `env` | object | Sets environment variables inside the sandbox. |
| `secrets` | array | Attaches project secrets by name. The sandbox sees each secret as an opaque placeholder. A name that is not a secret of the project is refused. |
| `network_policy` | object | Sets the outbound network policy with `block_all`, `allow_domains`, and `allow_cidrs`. `allow_domains` implies `block_all`. `allow_cidrs` restricts egress only together with `block_all` or `allow_domains`. A `*.` wildcard domain matches subdomains only, so list the parent domain separately. A create with a policy is refused when no runner in the region can enforce it for the sandbox's CPU architecture and type. You can [change it](/docs/network-limits#update-network-policy) after create. |
| `spot` | boolean | Runs the sandbox on discounted capacity that can be reclaimed. The default is `false`. |
| `region_id` | string | Sets the region, any listed region including `earth`. The default is the project's default region, then the organization's, then `earth`. A create in a region with no online Linux runner is refused. |
| `cpu_arch` | string | Sets the CPU architecture, `amd64` or `arm64`. The default is the region's default architecture, or `amd64` if the region sets none. A create with an architecture that no runner in the region provides is refused, or waits until its create deadline. |
| `cpu_type` | string | Sets the CPU hardware tier slug: `zen3`, `zen4`, `zen5`, `zen5c`, `arrowlake1`, `arrowlake2`, `graviton`, `graviton3`, and `graviton4`. The slug also sets the architecture. A create with a type that no runner in the region serves, itself or as a fallback, is refused, or waits until its create deadline. See [CPU types](#cpu-types). |
| `lifecycle_policy` | object | Sets the lifecycle policy with `timeout_seconds` and `on_timeout`, and `idle_expiry_seconds` and `on_idle_timeout`. The action is `delete`. By default, there is no idle timeout unless the project sets one, and the wall-clock timeout uses the project or platform default, if one is enabled. |
| `idempotency_key` | string | Makes a retried create return the same sandbox. You can also send it as the `Idempotency-Key` header. It is required when `region_id` is `earth` or another region that covers other regions. |
| `create_timeout_seconds` | integer | Sets how many seconds the sandbox has to reach running before it is deleted. `-1` sets the maximum, 86400. The default is 3600. |
| `wait_seconds` | integer | Sets how many seconds the server holds the request for the sandbox to start. `0` returns immediately. The default and the maximum are 3, and a larger value is lowered to 3. |

The response has the following fields:

| **Field**          | **Description**                                                                                                                                                       |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `status` | The status of the sandbox when the response is sent. The server holds the request for up to `wait_seconds`, so the status is `running`, `failed` when the sandbox failed to start, or an earlier status such as `pending` or `booting` when the sandbox has not started in time. Poll `GET /sandboxes/{sandboxId}?wait=running` while the status is not `running` or `failed`. A `failed` sandbox does not start; the `error` field of the sandbox names the cause. |
| `access_token` | The access token is returned only once. An idempotent replay returns `null`. |

</TabItem>
</Tabs>

### Spot [#spot]

Linux sandboxes run on reserved capacity by default. A spot Linux sandbox runs on discounted capacity that Daytona can reclaim at any time to free resources for full-price sandboxes. Spot multiplies the CPU, memory, and disk price by 0.7. Apart from price and reclaim, a spot Linux sandbox supports the same images, resources, volumes, and lifecycle operations as any other Linux sandbox.

A reclaim is immediate, with no advance notice and no grace period. An ephemeral sandbox is deleted, and only data on a [volume](/docs/volumes) or in other storage outside the sandbox remains. [Preemption](/docs/preemption) describes the reclaim policy.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create(spot=True)
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `spot` | bool | Places the sandbox on discounted, reclaimable capacity. The default is `False`. Set it when you create the sandbox. It cannot be changed on an existing sandbox. |

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create({ spot: true })
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `spot` | boolean | Places the sandbox on discounted, reclaimable capacity. The default is `false`. Set it when you create the sandbox. It cannot be changed on an existing sandbox. |

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

```bash
daytona sandbox create --spot
```

| **Flag** | **Type** | **Description** |
| -------- | -------- | --------------- |
| `--spot` | bool | Places the sandbox on discounted, reclaimable capacity. The default is `false`. Set it when you create the sandbox. It cannot be changed on an existing sandbox. |

</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 '{"spot": true}'
```

| **Field** | **Type** | **Description** |
| --------- | -------- | --------------- |
| `spot` | boolean | Places the sandbox on discounted, reclaimable capacity. The default is `false`. Set it when you create the sandbox. It cannot be changed on an existing sandbox. |

</TabItem>
</Tabs>

### CPU types [#cpu-types]

A CPU type is a processor model that a Linux sandbox can request when it is created. Each type belongs to one architecture, amd64 or arm64, and has a tier: its rank within that architecture, starting at 1 for the lowest. Requesting a CPU type also sets the sandbox's architecture.

The CPU type list contains every type that a create request accepts, whether or not a runner provides it. A create with a type that no runner in the region serves, itself or as a fallback, is refused, or waits until its create deadline. To see which types a region can serve, add the region. A type is available in a region when a running runner there provides it. When no runner provides the type itself, a runner with a higher tier of the same architecture can serve it as a fallback. Availability reflects the runners that are live at request time. [List regions](/docs/regions#list-regions) gives the region IDs.

<Tabs syncKey="language">
<TabItem label="CLI" icon="seti:shell">

```bash
# List CPU types
daytona cpu-type list

# Check CPU type availability in a region
daytona cpu-type list --region us-east-ash-1
```

| **Flag**   | **Type** | **Description**                                                                       |
| ---------- | -------- | ------------------------------------------------------------------------------------- |
| `--region` | string | Sets one region ID. Without it, the command lists CPU types without availability. With it, the output adds the `AVAILABLE` column. |

In a terminal, the output is a table with the following columns. Otherwise, the output is JSON unless `-o table` is set.

| **Column**  | **Description**                                                                                                                                   |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ID`        | The CPU type slug that a create request accepts.                                                                                                  |
| `NAME`      | The display name of the CPU type.                                                                                                                 |
| `ARCH`      | The CPU architecture, `amd64` or `arm64`.                                                                                                         |
| `TIER`      | The rank within the architecture, starting at 1 for the lowest.                                                                                   |
| `AVAILABLE` | Shown with `--region`. `exact` if a runner in the region provides the type, `fallback` if a higher tier of the same architecture serves it, and `-` otherwise. |

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

```bash
# List CPU types
curl 'https://api.daytona.com/cpu-catalog' \
  --header 'Authorization: Bearer YOUR_API_KEY'

# Check CPU type availability in a region
curl 'https://api.daytona.com/cpu-catalog?region_ids=us-east-ash-1' \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

| **Field**  | **Type** | **Description**                                                                                      |
| ---------- | -------- | ---------------------------------------------------------------------------------------------------- |
| `region_ids` | string | Sets a comma-separated list of region IDs, at most 64. The default is every region that the answering workload cell hosts. |

The response has the following fields:

| **Field**          | **Description**                                                                                                                                                                     |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `cpu_types` | Lists every CPU type with `id`, `name`, `cpu_arch`, and `tier`, and whether the requested regions can serve it: `available`, `exact_region_ids`, and `fallback_region_ids`. |
| `arches` | Lists each CPU architecture and the requested regions where it is available. |
| `regions` | Lists the covered regions. In each region, `default_arch` and `default_type` are the values that a create request that sets neither uses. `default_type` is `null` when the region sets none. |

</TabItem>
</Tabs>

## Filesystem snapshot [#filesystem-snapshot]

A filesystem snapshot saves the filesystem of a running Linux sandbox as an [image](/docs/images). The sandbox keeps running, and new sandboxes boot from the image with the captured files. Unlike a [memory snapshot](#memory-snapshot), a filesystem snapshot holds no processes or memory.

The capture runs in the background: the image starts as pending, moves to building, and becomes ready when the capture finishes. A named image is permanent until you delete it. An unnamed image is anonymous. Daytona deletes an anonymous image after its idle window passes without a sandbox create from it. The idle window is the server maximum of 7 days by default.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create()
sandbox.process.run("pip install requests")

# Capture the filesystem; the sandbox keeps running
image = sandbox.capture_image(name="my-env")

# Wait until the capture is ready, then boot new sandboxes from it
while image.status not in ("ready", "failed"):
    image = daytona.v2.images.get(image.id, wait="ready")
if image.status == "failed":
    raise RuntimeError(image.error)
clone = daytona.v2.create("my-env")
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `name` | str | Sets the image name. The default is `None`, which makes the image anonymous. The name must be unique in the project. |
| `idle_expiry_seconds` | int | Sets how many seconds an anonymous image can go without a sandbox create before deletion, from `1` to the server maximum. `-1` sets the maximum. The default is the server maximum. It applies only to anonymous images. A capture that also sets `name` is refused. |

<Callout type="note" title="Notes">
- The requests require the `write:images` and `write:sandboxes` permissions.
- The sandbox must be a running Linux sandbox.
</Callout>

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create()
await sandbox.process.run('pip install requests')

// Capture the filesystem; the sandbox keeps running
let image = await sandbox.captureImage({ name: 'my-env' })

// Wait until the capture is ready, then boot new sandboxes from it
while (image.status !== 'ready' && image.status !== 'failed') {
  image = await daytona.v2.images.get(image.id, { wait: 'ready' })
}
if (image.status === 'failed') throw new Error(image.error ?? 'image capture failed')
const clone = await daytona.v2.create('my-env')
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `name` | string | Sets the image name. The default is `undefined`, which makes the image anonymous. The name must be unique in the project. |
| `idleExpirySeconds` | number | Sets how many seconds an anonymous image can go without a sandbox create before deletion, from `1` to the server maximum. `-1` sets the maximum. The default is the server maximum. It applies only to anonymous images. A capture that also sets `name` is refused. |

<Callout type="note" title="Notes">
- The requests require the `write:images` and `write:sandboxes` permissions.
- The sandbox must be a running Linux sandbox.
</Callout>

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

```bash
# Capture the filesystem and wait until the image is ready
daytona image capture {sandboxId} --name my-env

# Boot a new sandbox from the captured filesystem
daytona sandbox create --image my-env
```

| **Flag** | **Type** | **Description** |
| -------- | -------- | --------------- |
| `--name` | string | Sets the image name. Without a name, the image is anonymous. The name must be unique in the project. |
| `--timeout` | string | Sets how long the command waits for the image to be ready. The default is `10m`. |
| `--no-wait` | boolean | Returns once the capture is queued, without waiting for the image to be ready. |

<Callout type="note" title="Notes">
- The requests require the `write:images` and `write:sandboxes` permissions.
- The sandbox must be a running Linux sandbox.
</Callout>

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

```bash
# Capture the filesystem; the sandbox keeps running
curl 'https://api.daytona.com/sandboxes/{sandboxId}/images' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{"name": "my-env"}'

# Wait for the capture to be ready
curl 'https://api.daytona.com/images/{imageId}?wait=ready' \
  --header 'Authorization: Bearer YOUR_API_KEY'

# Boot a new sandbox from the captured filesystem
curl 'https://api.daytona.com/sandboxes' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{"image": "my-env"}'
```

| **Field** | **Type** | **Description** |
| --------- | -------- | --------------- |
| `name` | string | Sets the image name. Without a name, the image is anonymous. The name must be unique in the project. |
| `idle_expiry_seconds` | integer | Sets how many seconds an anonymous image can go without a sandbox create before deletion, from `1` to the server maximum. `-1` sets the maximum. The default is the server maximum. It applies only to anonymous images. A capture that also sets `name` is refused. |

<Callout type="note" title="Notes">
- The requests require the `write:images` and `write:sandboxes` permissions.
- The sandbox must be a running Linux sandbox.
- The wait request returns at `ready` or `failed`, or after 30 seconds. Repeat it while the image status is `pending` or `building`. A `failed` image does not become `ready`.
</Callout>

</TabItem>
</Tabs>

## Memory snapshot [#memory-snapshot]

A memory snapshot saves the memory and disk of a running Linux sandbox under a name. A sandbox restored from the snapshot resumes the captured processes and memory instead of booting. The restored sandbox gets the CPU, memory, and disk of the source sandbox. Deleting the source sandbox does not delete its snapshots.

The capture runs in the background: the snapshot starts as pending, is building while the runner captures the sandbox, and becomes ready when the capture finishes. A snapshot restores on the runner that captured it, or on another runner of the region with the same CPU model and hypervisor version. It restores in another region only where Daytona has enabled cross-region restore and the source sandbox was not persistent.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create()

# Capture the memory and disk of the running sandbox
snapshot = sandbox.create_snapshot("my-snapshot")

# Wait until the capture is ready
while snapshot.status not in ("ready", "failed"):
    snapshot = daytona.v2.snapshots.get(snapshot.id, wait="ready")
if snapshot.status == "failed":
    raise RuntimeError(snapshot.error)

# Resume the captured processes and memory in a new sandbox
restored = daytona.v2.create_from_snapshot("my-snapshot", labels={"team": "research"})
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `name` | str | Sets the snapshot name, 1 to 128 characters of letters, digits, `.`, `_`, and `-`. The name cannot start with `.` or with a reserved prefix: `sbx_`, `vol_`, `fn_`, `img_`, `snap_`, `snap-`, `build-`, `refs`, `by-digest`, `prj-`, or `glb-`. This parameter is required. Snapshots and images in the project share one name space. A name in use fails with `409`. |
| `snapshot` | str | Sets the snapshot that `create_from_snapshot()` restores from, by name or by ID, `snap_...`. This parameter is required. |
| `labels` | Dict\[str, str\] | Attaches key-value metadata to the restored sandbox. The restored sandbox does not inherit the labels of the source sandbox. |

<Callout type="note" title="Notes">
- The requests require the `write:snapshots` and `write:sandboxes` permissions.
- The source sandbox must be running.
- The source sandbox must be persistent or served from a warm template. A snapshot of any other sandbox, such as one created from a filesystem snapshot or with volumes attached, fails with `409`.
</Callout>

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create()

// Capture the memory and disk of the running sandbox
let snapshot = await sandbox.createSnapshot('my-snapshot')

// Wait until the capture is ready
while (snapshot.status !== 'ready' && snapshot.status !== 'failed') {
  snapshot = await daytona.v2.snapshots.get(snapshot.id, { wait: 'ready' })
}
if (snapshot.status === 'failed') throw new Error(snapshot.error ?? 'snapshot capture failed')

// Resume the captured processes and memory in a new sandbox
const restored = await daytona.v2.createFromSnapshot('my-snapshot', { labels: { team: 'research' } })
```

| **Parameter** | **Type** | **Description** |
| ------------- | -------- | --------------- |
| `name` | string | Sets the snapshot name, 1 to 128 characters of letters, digits, `.`, `_`, and `-`. The name cannot start with `.` or with a reserved prefix: `sbx_`, `vol_`, `fn_`, `img_`, `snap_`, `snap-`, `build-`, `refs`, `by-digest`, `prj-`, or `glb-`. This parameter is required. Snapshots and images in the project share one name space. A name in use fails with `409`. |
| `snapshot` | string | Sets the snapshot that `createFromSnapshot()` restores from, by name or by ID, `snap_...`. This parameter is required. |
| `labels` | Record\<string, string> | Attaches key-value metadata to the restored sandbox. The restored sandbox does not inherit the labels of the source sandbox. |

<Callout type="note" title="Notes">
- The requests require the `write:snapshots` and `write:sandboxes` permissions.
- The source sandbox must be running.
- The source sandbox must be persistent or served from a warm template. A snapshot of any other sandbox, such as one created from a filesystem snapshot or with volumes attached, fails with `409`.
</Callout>

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

```bash
# Capture the memory and disk of the running sandbox and wait until it is ready
daytona snapshot create {sandboxId} --name my-snapshot

# Resume the captured processes and memory in a new sandbox
daytona sandbox create-from-snapshot my-snapshot --label team=research
```

| **Flag** | **Type** | **Description** |
| -------- | -------- | --------------- |
| `--name` | string | Sets the snapshot name. This flag is required. |
| `--label` | KEY=VALUE | Attaches a `KEY=VALUE` metadata label to the restored sandbox. The restored sandbox does not inherit the labels of the source sandbox. Repeat the flag for more labels. |
| `--timeout` | string | Sets how long the command waits for the snapshot to be `ready`. The default is `10m`. |
| `--no-wait` | boolean | Returns once the capture is queued, without waiting for `ready`. |

<Callout type="note" title="Notes">
- The requests require the `write:snapshots` and `write:sandboxes` permissions.
- The source sandbox must be running.
- The source sandbox must be persistent or served from a warm template. A snapshot of any other sandbox, such as one created from a filesystem snapshot or with volumes attached, fails with `409`.
</Callout>

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

```bash
# Capture the memory and disk of the running sandbox
curl 'https://api.daytona.com/sandboxes/{sandboxId}/snapshots' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{"name": "my-snapshot"}'

# Wait for the capture to be ready
curl 'https://api.daytona.com/snapshots/{snapshotId}?wait=ready&timeout_ms=60000' \
  --header 'Authorization: Bearer YOUR_API_KEY'

# Resume the captured processes and memory in a new sandbox
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", "labels": {"team": "research"}}'
```

| **Field** | **Type** | **Description** |
| --------- | -------- | --------------- |
| `name` | string | Sets the snapshot name, 1 to 128 characters of letters, digits, `.`, `_`, and `-`. The name cannot start with `.` or with a reserved prefix: `sbx_`, `vol_`, `fn_`, `img_`, `snap_`, `snap-`, `build-`, `refs`, `by-digest`, `prj-`, or `glb-`. This field is required. Snapshots and images in the project share one name space. A name in use fails with `409`. |
| `snapshot` | string | Sets the snapshot that `POST /sandboxes/from-snapshot` restores from, by name or by ID, `snap_...`. This field is required. |
| `labels` | object | Attaches key-value metadata to the restored sandbox. The restored sandbox does not inherit the labels of the source sandbox. |

<Callout type="note" title="Notes">
- The requests require the `write:snapshots` and `write:sandboxes` permissions.
- The source sandbox must be running.
- The source sandbox must be persistent or served from a warm template. A snapshot of any other sandbox, such as one created from a filesystem snapshot or with volumes attached, fails with `409`.
- The wait request returns at `ready` or `failed`, or after 60 seconds. Repeat it while the snapshot status is `pending` or `building`. A `failed` snapshot does not become `ready`.
- A restore from a snapshot that is not ready is refused.
</Callout>

</TabItem>
</Tabs>

## Filesystem persistence [#filesystem-persistence]

Filesystem persistence keeps the contents of a sandbox's disk: files, installed packages, cloned repositories, and build artifacts. A sandbox with a preserved filesystem starts with its environment intact, with nothing to reinstall or rebuild.

A Linux sandbox keeps its filesystem on its host until it is deleted. Deleting the sandbox or losing its host discards the filesystem. [Filesystem snapshots](#filesystem-snapshot) keep the filesystem beyond the sandbox, and new sandboxes boot from them.

## Memory persistence [#memory-persistence]

Memory persistence keeps the runtime state of a sandbox: running processes, open connections, and everything loaded in RAM. A sandbox with preserved memory continues from the point it was frozen, with processes still running, instead of starting from a clean boot.

A Linux sandbox keeps its memory only while it runs. [Memory snapshots](#memory-snapshot) keep memory and processes beyond the sandbox.

## Lifecycle [#lifecycle]

Every Linux sandbox moves through a lifecycle. A Linux sandbox can have several different states. Each state reflects the status of your sandbox. A Linux sandbox transitions between states in response to user actions, or automatically when one of its [timeouts](#timeouts) elapses.

Every Linux sandbox supports wait for state, delete, timeouts, and lifecycle policy updates. A Linux sandbox keeps its filesystem and memory until it is deleted, or until its host fails: the sandbox then moves to error (lost in the CLI and API), and its local filesystem and memory are gone.

<SandboxDiagram />

The following tables list the states of a Linux sandbox and the transitions between them. The SDKs report the states in the **State** column. The CLI and API report the more detailed status in the **API status** column.

<Collapsible title="Sandbox states">

| **State**        | **API status**                 | **Description**                                                                 |
| ---------------- | ------------------------------ | ------------------------------------------------------------------------------- |
| **`queued`**     | **`queued`**                   | The create request is recorded and waits to be published for placement.         |
| **`creating`**   | **`pending`**, **`assigned`**  | The create request is accepted, and the sandbox is queued for and placed on a host. |
| **`starting`**   | **`booting`**                  | The microVM is booting and will be ready to use.                                |
| **`started`**    | **`running`**                  | The sandbox is running and ready to accept requests.                            |
| **`destroying`** | **`deleting`**                 | The sandbox is being deleted.                                                   |
| **`destroyed`**  | **`deleted`**                  | The sandbox and its storage are removed.                                        |
| **`error`**      | **`failed`**, **`lost`**       | The sandbox could not boot, hit an unrecoverable error, or its host was lost.   |
| **`unknown`**    |                                | The SDK does not recognize the status the API reports.                          |

</Collapsible>

A sandbox can transition between states in response to various actions. The following table lists the initial state, target state, and trigger for the transition.

<Collapsible title="State transitions">

| **Initial state** | **Target state** | **Trigger**                                                                        |
| ----------------- | ---------------- | ---------------------------------------------------------------------------------- |
| **`queued`**      | **`creating`**   | The create request is published for placement.                                     |
| **`creating`**    | **`starting`**   | The sandbox is placed on a host, the host prepares its image, and the microVM boots. |
| **`starting`**    | **`started`**    | The sandbox finishes booting and accepts requests.                                 |
| any state         | **`destroying`** | A delete is requested, a timeout elapses, or the platform reclaims a spot sandbox. |
| **`destroying`**  | **`destroyed`**  | The sandbox is removed and its resources are released.                             |
| any active state  | **`error`**      | The sandbox fails to boot, hits an unrecoverable error, or its host is lost.       |

</Collapsible>

### Wait for state [#wait-for-state]

Wait until a Linux sandbox reaches a target state. The wait stops early when the sandbox reaches a state from which the target is no longer reachable, such as error or destroyed. The SDKs use the states in the [sandbox states](#lifecycle) table, so the SDK started state corresponds to the running status in the CLI and API.

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

```python
# Block until the sandbox is started; returns the sandbox
sandbox.wait(until="started", timeout=60)

# Block until the sandbox is in one of the listed states
sandbox.wait(until=["starting", "started"], timeout=60)
```

| **Parameter** | **Type**  | **Description**                                                                                                                  |
| ------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `until` | str \| Sequence\[str\] | Sets one state or a list of states. `wait()` returns on any of them. The default is `"started"`. |
| `timeout` | float | Sets the wait limit in seconds. When the timeout elapses, `wait()` raises `RequestTimeoutError`. When the sandbox reaches `destroying`, `destroyed`, or `error` first, it raises `SandboxTerminalStateError`. `0` waits without a limit. The default is `60`. |

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

```typescript
// Block until the sandbox is started; returns the sandbox
await sandbox.wait({ until: 'started', timeoutSeconds: 60 })

// Block until the sandbox is in one of the listed states
await sandbox.wait({ until: ['starting', 'started'], timeoutSeconds: 60 })
```

| **Parameter** | **Type** | **Description**                                                                                                            |
| ------------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| `until` | SandboxWaitState \| SandboxWaitState\[\] | Sets one state or a list of states. `wait()` returns on any of them. The default is `'started'`. |
| `timeoutSeconds` | number | Sets the wait limit in seconds. When the timeout elapses, `wait()` throws `RequestTimeoutError`. When the sandbox reaches `destroying`, `destroyed`, or `error` first, it throws `SandboxTerminalStateError`. `0` waits without a limit. The default is `60`. |

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

```bash
# Block until the sandbox is running, or the timeout elapses
daytona sandbox wait {sandboxId} --for running --timeout 60s
```

| **Flag** | **Type** | **Description** |
| -------- | -------- | --------------- |
| `--for` | string | Sets the state to wait for: `running`, `stopped`, `paused`, or `deleted`. The SDK names `started` and `destroyed` are also accepted. The default is `running`. |
| `--timeout` | string | Sets how long the command waits. The default is `10m`. |

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

```bash
# Long-poll until the sandbox is running, a terminal state, or the timeout elapses
curl 'https://api.daytona.com/sandboxes/{sandboxId}?wait=running&timeout_ms=60000' \
  --header 'Authorization: Bearer YOUR_API_KEY'

# Long-poll until the sandbox is exactly deleted; wait_exact skips the transient deleting state
curl 'https://api.daytona.com/sandboxes/{sandboxId}?wait_exact=deleted&timeout_ms=60000' \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

| **Field**    | **Type**  | **Description**                                                                                             |
| ------------ | --------- | ----------------------------------------------------------------------------------------------------------- |
| `wait`       | string  | Blocks the response until the sandbox reaches this state or a terminal state. The wait also ends on `stopping`, `stopped`, `deleting`, `deleted`, `failed`, or `lost`. There is no default. |
| `wait_exact` | string  | Blocks the response until the sandbox reaches exactly this state. Only `failed` and `lost` also end the wait. There is no default. |
| `timeout_ms` | integer | Sets the wait limit in milliseconds, at most `60000`. A larger value is lowered to `60000`. When the limit elapses, the response is `200` with the current sandbox. Check `status` in the response. The default is `30000`. |

</TabItem>
</Tabs>

### Delete [#delete]

Delete a Linux sandbox to tear down its virtual machine. Deletion works in any state. The API returns once teardown starts, and the SDKs and the CLI wait until the sandbox is deleted. The sandbox moves from deleting to deleted when the teardown finishes. Deleting a sandbox discards its filesystem and memory. Images and snapshots captured from the sandbox remain.

To keep files from a sandbox, take a [filesystem snapshot](#filesystem-snapshot) or write the files to a [volume](/docs/volumes) or other storage outside the sandbox.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create()

sandbox.delete()

# Delete by sandbox ID, without fetching the sandbox first
daytona.v2.delete("{sandboxId}")
```

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create()

await sandbox.delete()

// Delete by sandbox ID, without fetching the sandbox first
await daytona.v2.delete('{sandboxId}')
```

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

```bash
daytona sandbox delete {sandboxId}
```

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

```bash
curl 'https://api.daytona.com/sandboxes/{sandboxId}' \
  --request DELETE \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

</TabItem>
</Tabs>

### Timeouts [#timeouts]

Daytona deletes a Linux sandbox automatically when one of its two timers elapses. Each timer pairs an interval in seconds with the action it fires. Set both timers at create in the lifecycle policy, and change them later through [update lifecycle policy](#update-lifecycle-policy).

| **Timer**                         | **Purpose**                                         | **Fires after**                                              | **Default**                 |
| --------------------------------- | --------------------------------------------------- | ------------------------------------------------------------ | --------------------------- |
| [**Timeout**](#timeout)           | Cap how long a sandbox lives                        | The interval has passed since the sandbox last started running, active or not | Project or platform default |
| [**Idle timeout**](#idle-timeout) | Delete a sandbox that is not in use                 | The sandbox has had no activity for the interval             | Project default, or off     |

The action for both timers is delete. Auto-delete is not a separate setting. It is the idle timeout with the delete action.

#### Timeout [#timeout]

The timeout is a wall-clock budget. It starts when the sandbox starts running. Activity does not extend it. A delete timeout fires in any state, except while the sandbox is still being created: a sandbox that does not reach running is deleted at its create deadline. Once set, the timeout cannot be cleared.

When the timeout is omitted at create, Daytona applies the project's [lifecycle defaults](/docs/projects#lifecycle-defaults). Without a project default, Daytona applies the platform default timeout of 300 seconds, if the platform default is enabled. An explicit timeout must not exceed the organization maximum, 86,400 seconds (24 hours) unless the organization sets a different maximum.

When the action is omitted, it defaults to delete.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create(
    # Delete the sandbox 2 hours after it is created
    lifecycle_policy={"timeout_seconds": 7200, "on_timeout": "delete"},
)
```

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create({
  // Delete the sandbox 2 hours after it is created
  lifecyclePolicy: { timeoutSeconds: 7200, onTimeout: 'delete' },
})
```

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

```bash
# Delete the sandbox 2 hours after it is created
daytona sandbox create --lifecycle-timeout 2h --on-lifecycle-timeout delete
```

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

```bash
# Delete the sandbox 2 hours after it is created
curl 'https://api.daytona.com/sandboxes' \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{
  "lifecycle_policy": { "timeout_seconds": 7200, "on_timeout": "delete" }
}'
```

</TabItem>
</Tabs>

#### Idle timeout [#idle-timeout]

The idle timeout fires after the sandbox has had no activity for the interval. Activity is any request through the toolbox API, preview URLs, VNC, and SSH, a toolbox command that is still running, the sandbox being created or starting to run, and a reset of the idle timer. A change to the lifecycle policy does not count as activity. The idle timeout is off by default unless the project sets one, has a minimum of 60 seconds, and requires an action. The API raises a smaller value to 60 seconds, and the CLI refuses it. The action fires within about 2 minutes after the interval elapses.

##### Auto-delete [#auto-delete]

Delete a Linux sandbox after a period of inactivity.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create(
    lifecycle_policy={"idle_expiry_seconds": 3600, "on_idle_timeout": "delete"},
)
```

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create({
  lifecyclePolicy: { idleExpirySeconds: 3600, onIdleTimeout: 'delete' },
})
```

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

```bash
daytona sandbox create --idle-timeout 1h --on-idle-timeout delete
```

</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 '{
  "lifecycle_policy": { "idle_expiry_seconds": 3600, "on_idle_timeout": "delete" }
}'
```

</TabItem>
</Tabs>

##### Reset the idle timer [#reset-the-idle-timer]

Reset the idle timer of a Linux sandbox to keep it alive while it does work that Daytona does not count as activity. The reset counts as activity, so the idle countdown restarts from now. The timeout is not affected.

The reset succeeds whether or not an idle timeout is set, in any state except deleting and deleted. It never moves the timer backwards: when newer activity arrives at the same time, the newer activity wins.

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

```python
from daytona import Daytona

daytona = Daytona()
sandbox = daytona.v2.create(
    lifecycle_policy={"idle_expiry_seconds": 3600, "on_idle_timeout": "delete"},
)

lifecycle = sandbox.reset_idle_timer()
print(lifecycle.idle_timeout_at)
```

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- When the idle action is delete, the request also requires the `delete:sandboxes` permission.
</Callout>

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create({
  lifecyclePolicy: { idleExpirySeconds: 3600, onIdleTimeout: 'delete' },
})

const lifecycle = await sandbox.resetIdleTimer()
console.log(lifecycle.idleTimeoutAt)
```

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- When the idle action is delete, the request also requires the `delete:sandboxes` permission.
</Callout>

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

```bash
curl 'https://api.daytona.com/sandboxes/{sandboxId}/reset-idle-timer' \
  --request POST \
  --header 'Authorization: Bearer YOUR_API_KEY'
```

The response has the sandbox ID and its lifecycle policy with the following fields:

| **Field**         | **Description**                          |
| ----------------- | ---------------------------------------- |
| `idle_timeout_at` | The reset moves this value forward.      |
| `timeout_at`      | The reset leaves this value unchanged.   |

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- When the idle action is delete, the request also requires the `delete:sandboxes` permission.
</Callout>

</TabItem>
</Tabs>

### Update lifecycle policy [#update-lifecycle-policy]

Update the timeouts of an existing Linux sandbox. Omitted fields keep their current values. The new actions must be valid for the sandbox, as listed in [timeouts](#timeouts). A deleting or deleted sandbox cannot be updated.

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

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

daytona = Daytona()
sandbox = daytona.v2.create()

# Delete the sandbox after 30 minutes without activity; omitted fields keep their current value
lifecycle = sandbox.update_lifecycle_policy(idle_expiry_seconds=1800, on_idle_timeout="delete")
print(lifecycle.idle_expiry_seconds, lifecycle.on_idle_timeout)

# Re-anchor the timeout to 1 hour from now
lifecycle = sandbox.update_lifecycle_policy(timeout_seconds=3600)
print(lifecycle.timeout_at)

# Clear the idle timeout
lifecycle = sandbox.update_lifecycle_policy(idle_expiry_seconds=DISABLED)
```

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- Setting, changing, or clearing a delete action also requires the `delete:sandboxes` permission.
</Callout>

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

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

const daytona = new Daytona()
const sandbox = await daytona.v2.create()

// Delete the sandbox after 30 minutes without activity; omitted fields keep their current value
let lifecycle = await sandbox.updateLifecyclePolicy({ idleExpirySeconds: 1800, onIdleTimeout: 'delete' })
console.log(lifecycle.idleExpirySeconds, lifecycle.onIdleTimeout)

// Re-anchor the timeout to 1 hour from now
lifecycle = await sandbox.updateLifecyclePolicy({ timeoutSeconds: 3600 })
console.log(lifecycle.timeoutAt)

// Clear the idle timeout
lifecycle = await sandbox.updateLifecyclePolicy({ idleExpirySeconds: DISABLED })
```

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- Setting, changing, or clearing a delete action also requires the `delete:sandboxes` permission.
</Callout>

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

```bash
# Delete the sandbox after 30 minutes without activity
daytona sandbox update {sandboxId} --idle-timeout 30m --on-idle-timeout delete

# Re-anchor the timeout to 1 hour from now
daytona sandbox update {sandboxId} --lifecycle-timeout 1h

# Clear the idle timeout
daytona sandbox update {sandboxId} --idle-timeout off
```

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- Setting, changing, or clearing a delete action also requires the `delete:sandboxes` permission.
</Callout>

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

```bash
# Delete the sandbox after 30 minutes without activity
curl 'https://api.daytona.com/sandboxes/{sandboxId}/lifecycle-policy' \
  --request PATCH \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{ "idle_expiry_seconds": 1800, "on_idle_timeout": "delete" }'

# Re-anchor the timeout to 1 hour from now
curl 'https://api.daytona.com/sandboxes/{sandboxId}/lifecycle-policy' \
  --request PATCH \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{ "timeout_seconds": 3600 }'

# Clear the idle timeout
curl 'https://api.daytona.com/sandboxes/{sandboxId}/lifecycle-policy' \
  --request PATCH \
  --header 'Content-Type: application/json' \
  --header 'Authorization: Bearer YOUR_API_KEY' \
  --data '{ "idle_expiry_seconds": -1 }'
```

| **Field**           | **Type**  | **Description**                                                                                                   |
| ------------------- | --------- | ----------------------------------------------------------------------------------------------------------------- |
| `timeout_seconds` | integer | Sets the seconds until the timeout, counted from now. If omitted, the value is unchanged. |
| `idle_expiry_seconds` | integer | Sets the seconds without activity before the idle action. `-1` clears the idle timeout and its action. If omitted, the value is unchanged. |
| `on_timeout` | string | Sets the timeout action, `delete`. If omitted, the value is unchanged. |
| `on_idle_timeout` | string | Sets the idle action, `delete`. It is required when you set an idle timeout on a sandbox that has none. If omitted, the value is unchanged. |

<Callout type="note" title="Notes">
- The request requires the `write:sandboxes` permission.
- Setting, changing, or clearing a delete action also requires the `delete:sandboxes` permission.
</Callout>

</TabItem>
</Tabs>

## Permissions [#permissions]

Linux sandboxes use the sandbox permissions of their project, and snapshots use the image and snapshot permissions. You can grant each to an [organization role](/docs/organizations#roles) or an [API key](/docs/api-keys).

Setting, changing, or clearing a delete action in a lifecycle policy, and resetting the idle timer of a sandbox whose idle action is delete, also require the permission to delete sandboxes. The [audit logs](/docs/audit-logs) record sandbox creates, lifecycle changes, deletes, and snapshots.

| **Permission**         | **Grants**                                                                  |
| ---------------------- | --------------------------------------------------------------------------- |
| **`read:sandboxes`**   | Get sandboxes and wait for their state                                      |
| **`write:sandboxes`**  | Create sandboxes, change their lifecycle policy, and reset the idle timer   |
| **`delete:sandboxes`** | Delete sandboxes                                                            |
| **`write:images`**     | Capture filesystem snapshots as images                                      |
| **`write:snapshots`**  | Create memory snapshots                                                     |
