# Managing Sandbox Snapshots — Capture sandbox state and restore it in new sandboxes.


> *Render Sandboxes is in public beta.*
>
> APIs, defaults, and limits might change during the beta period.

After you [create a sandbox](sandboxes-creating), you can capture its state in a *snapshot*. You can restore a snapshot to create new sandboxes with the same prepared filesystem or resume a process from a saved state.

Snapshots are useful for reusing installed packages, preparing environments for agents, and saving progress before a sandbox terminates.

A sandbox must be actively running to capture a snapshot. Creating a snapshot does not terminate the sandbox.

## Kinds of snapshots

Render supports two kinds of sandbox snapshots:

| Kind | Description |
| --- | --- |
| *Runtime snapshot* | Captures the writable filesystem, along with memory and CPU state. Use this to resume running processes from their captured state in a new sandbox. Must restore onto the exact same compute plan as the source sandbox. |
| *Filesystem snapshot* | Captures the writable filesystem only. Use this to reuse files and installed packages in a new sandbox, without preserving running processes. Can restore onto any supported compute plan. |

## Capturing a snapshot

The following example captures a filesystem snapshot and waits until it's available. Replace `sbx-abc123` with your sandbox's ID:

**Tab: CLI**

```shell
render sandboxes snapshots create sbx-abc123 --kind filesystem --wait
```

The command prints the snapshot's ID and details after capture completes.

**Tab: TypeScript**

```typescript
import { Render } from '@renderinc/sdk'

const sandboxes = new Render().sandboxes

const snapshot = await sandboxes.snapshots.create({
  sandboxId: 'sbx-abc123',
  kind: 'filesystem',
  wait: true
})

console.log(snapshot.id, snapshot.status)
```

Call [`snapshots.create`](sandboxes-sdk-typescript#snapshots-create) with the source sandbox's ID and the snapshot options.

**Tab: Python (sync)**

```python
from render import Render

sandboxes = Render().sandboxes

snapshot = sandboxes.snapshots.create(
    "sbx-abc123",
    kind="filesystem",
    wait=True,
)

print(snapshot.id, snapshot.status)
```

Call [`snapshots.create`](sandboxes-sdk-python#snapshots-create) with the source sandbox's ID and the snapshot options as keyword parameters.

**Tab: Python (async)**

```python
import asyncio
from render import RenderAsync

async def main():
    sandboxes = RenderAsync().sandboxes

    snapshot = await sandboxes.snapshots.create(
        "sbx-abc123",
        kind="filesystem",
        wait=True,
    )

    print(snapshot.id, snapshot.status)

asyncio.run(main())
```

Call [`snapshots.create`](sandboxes-sdk-python#snapshots-create) with the source sandbox's ID and the snapshot options as keyword parameters.

To capture a runtime snapshot instead, set the kind to `runtime` or omit the kind option.

The wait option waits up to *five minutes* for capture to complete. If you omit it, creation returns before the snapshot is available. If the wait times out, capture continues. Check the snapshot's [current status](#retrieving-snapshot-details) before starting another capture.

## Restoring a snapshot

Restore a snapshot by providing its ID when you create a sandbox. Each restore creates a new sandbox, preserving the snapshot for reuse.

Snapshots always belong to the same [sandbox group](sandboxes-creating#sandbox-groups) as their source sandbox. Provide that group's ID when restoring. You can restore a snapshot only into another sandbox in the same group.

**Tab: CLI**

Replace `snp-abc123` with the ID returned by snapshot creation and `sbg-abc123` with its sandbox group ID. You can find group IDs with `render sandbox-groups list`:

```shell
render sandboxes create --snapshot-id snp-abc123 \
  --group sbg-abc123 --timeout=300 --wait
```

**Tab: TypeScript**

```typescript
const restored = await sandboxes.create({
  snapshotId: snapshot.id,
  sandboxGroupId: snapshot.sandboxGroupId,
  timeoutSeconds: 300,
  wait: true
})

console.log(restored.id, restored.status)
```

**Tab: Python (sync)**

```python
restored = sandboxes.create(
    snapshot_id=snapshot.id,
    sandbox_group_id=snapshot.sandbox_group_id,
    timeout_seconds=300,
    wait=True,
)

print(restored.id, restored.status)
```

**Tab: Python (async)**

```python
restored = await sandboxes.create(
    snapshot_id=snapshot.id,
    sandbox_group_id=snapshot.sandbox_group_id,
    timeout_seconds=300,
    wait=True,
)

print(restored.id, restored.status)
```

These examples wait until the restored sandbox is running and set a five-minute lifetime. You can then [execute commands](sandboxes-executing) or [manage files](sandboxes-files) inside it.

### Restored state and configuration

Restoring a snapshot preserves some aspects of the source sandbox, while other settings come from the new create request or their defaults. See [Configuring sandbox behavior](sandboxes-creating#configuring-sandbox-behavior) for how to provide these settings with the CLI or SDKs.

| Property | Preserved? | Notes |
| --- | --- | --- |
| *Filesystem* | ☑️ |  |
| *Running processes* | ☑️ | Runtime snapshots only. |
| *Compute plan* | ☑️ | Preserved by default. Filesystem snapshots support choosing a different plan. |
| *Network policy* | ➖ | Defaults to `allow-all`. Provide restrictions again to retain them. |
| *Environment variables* | ➖ | New commands use newly provided variables. Resumed processes retain their environment. |
| *Runtime timeout* | ➖ | Defaults to 24 hours. |
| *Idle timeout* | ➖ | Defaults to 15 minutes. |

### Restoring by name

You can name a snapshot when you capture it, then restore it by name instead of ID:

**Tab: CLI**

Replace `sbg-abc123` with the group ID of the source sandbox (`sbx-abc123`):

```shell
render sandboxes snapshots create sbx-abc123 \
  --kind filesystem --name prepared-env --wait

render sandboxes create --from prepared-env --group sbg-abc123 --wait
```

The `--from` flag accepts either a snapshot name or ID. Do not combine it with `--snapshot-id`.

**Tab: TypeScript**

```typescript
const snapshot = await sandboxes.snapshots.create({
  sandboxId: 'sbx-abc123',
  kind: 'filesystem',
  name: 'prepared-env',
  wait: true
})

const restored = await sandboxes.create({
  snapshotName: 'prepared-env',
  sandboxGroupId: snapshot.sandboxGroupId,
  wait: true
})
```

**Tab: Python (sync)**

```python
snapshot = sandboxes.snapshots.create(
    "sbx-abc123",
    kind="filesystem",
    name="prepared-env",
    wait=True,
)

restored = sandboxes.create(
    snapshot_name="prepared-env",
    sandbox_group_id=snapshot.sandbox_group_id,
    wait=True,
)
```

**Tab: Python (async)**

```python
snapshot = await sandboxes.snapshots.create(
    "sbx-abc123",
    kind="filesystem",
    name="prepared-env",
    wait=True,
)

restored = await sandboxes.create(
    snapshot_name="prepared-env",
    sandbox_group_id=snapshot.sandbox_group_id,
    wait=True,
)
```

Names are case-sensitive and scoped to a sandbox group. If you reuse a name, restoring by that name uses the most recently available snapshot with that name in the selected sandbox group.

A snapshot's name must be between 1 and 64 characters and cannot begin with `snp-`.

## Retrieving snapshot details

You can retrieve a snapshot to check its status, capture error, expiration time, and other details:

**Tab: CLI**

```shell
render sandboxes snapshots get snp-abc123 --group sbg-abc123
```

**Tab: TypeScript**

```typescript
const currentSnapshot = await sandboxes.snapshots.get({
  sandboxGroupId: snapshot.sandboxGroupId,
  snapshotId: snapshot.id
})

console.log(currentSnapshot.status, currentSnapshot.error)
```

**Tab: Python (sync)**

```python
current_snapshot = sandboxes.snapshots.from_id(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)

print(current_snapshot.status, current_snapshot.error)
```

**Tab: Python (async)**

```python
current_snapshot = await sandboxes.snapshots.from_id(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)

print(current_snapshot.status, current_snapshot.error)
```

Lookup, listing, and deletion methods all require the snapshot's sandbox group ID.

### Snapshot status

A snapshot has one of the following statuses:

| Status | Meaning |
| --- | --- |
| `creating` | Capture is in progress. The snapshot cannot yet be restored. |
| `available` | Capture succeeded. You can restore the snapshot. |
| `failed` | Capture failed. Check the snapshot's `error` field for details. |

### Waiting for an existing snapshot

If you [captured a snapshot](#capturing-a-snapshot) without waiting, you can wait for it to become available with the following approaches:

**Tab: CLI**

Use `render sandboxes snapshots get` to check the snapshot's status:

```shell
render sandboxes snapshots get snp-abc123 --group sbg-def456
```

To wait in a script, call this command in a polling loop while the status is `creating`, pausing between checks. Stop when the status is `available` or `failed`. Add `--output json` to read the status programmatically.

**Tab: TypeScript**

```typescript
const availableSnapshot = await sandboxes.snapshots.waitUntilAvailable({
  sandboxGroupId: snapshot.sandboxGroupId,
  snapshotId: snapshot.id
})
```

**Tab: Python (sync)**

```python
available_snapshot = sandboxes.snapshots.wait_until_available(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)
```

**Tab: Python (async)**

```python
available_snapshot = await sandboxes.snapshots.wait_until_available(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)
```

The SDK methods wait up to five minutes by default and raise an error if capture fails or the wait times out.

## Snapshot expiration

By default, snapshots expire 30 days after capture. This expiration time does _not_ reset if you use the snapshot to restore a sandbox.

Check `expiresAt` (TypeScript) or `expires_at` (Python) for an individual snapshot's expiration time. The CLI displays this value in snapshot details.

You can set an expiration time when capturing a snapshot with either SDK. The following example sets it to 24 hours from now:

**Tab: TypeScript**

```typescript
const snapshot = await sandboxes.snapshots.create({
  sandboxId: 'sbx-abc123',
  kind: 'filesystem',
  expiresAt: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
  wait: true
})
```

**Tab: Python (sync)**

```python
from datetime import datetime, timedelta, timezone

snapshot = sandboxes.snapshots.create(
    "sbx-abc123",
    kind="filesystem",
    expires_at=datetime.now(timezone.utc) + timedelta(hours=24),
    wait=True,
)
```

**Tab: Python (async)**

```python
from datetime import datetime, timedelta, timezone

snapshot = await sandboxes.snapshots.create(
    "sbx-abc123",
    kind="filesystem",
    expires_at=datetime.now(timezone.utc) + timedelta(hours=24),
    wait=True,
)
```

The expiration time must be in the future. After a snapshot expires, you can no longer retrieve or restore it. Sandboxes already restored from an expired snapshot are unaffected.

## Listing snapshots

List snapshots in a sandbox group to find their IDs and statuses. The following example lists snapshots that are available to restore:

**Tab: CLI**

```shell
render sandboxes snapshots list --group sbg-abc123 --status available
```

**Tab: TypeScript**

```typescript
const entries = await sandboxes.snapshots.list({
  sandboxGroupId: snapshot.sandboxGroupId,
  status: ['available']
})

for (const { snapshot } of entries) {
  console.log(snapshot.id, snapshot.name, snapshot.status)
}
```

**Tab: Python (sync)**

```python
page = sandboxes.snapshots.list(
    sandbox_group_id=snapshot.sandbox_group_id,
    status="available",
)

for listed_snapshot in page.snapshots:
    print(listed_snapshot.id, listed_snapshot.name, listed_snapshot.status)
```

**Tab: Python (async)**

```python
page = await sandboxes.snapshots.list(
    sandbox_group_id=snapshot.sandbox_group_id,
    status="available",
)

for listed_snapshot in page.snapshots:
    print(listed_snapshot.id, listed_snapshot.name, listed_snapshot.status)
```

Results are ordered newest first. Omit the status filter to include snapshots with any status. Deleted and expired snapshots are excluded.

The SDKs return one page at a time. Use the cursor from the last entry (TypeScript) or `next_cursor` (Python) to retrieve additional pages. For pagination options, see the [TypeScript](sandboxes-sdk-typescript#snapshots-list) and [Python](sandboxes-sdk-python#snapshots-list) references.

## Deleting a snapshot

Delete a snapshot when you no longer need to restore from it:

**Tab: CLI**

```shell
render sandboxes snapshots delete snp-abc123 --group sbg-abc123 --confirm
```

Without `--confirm`, the command previews the deletion and makes no changes.

**Tab: TypeScript**

```typescript
await sandboxes.snapshots.delete({
  sandboxGroupId: snapshot.sandboxGroupId,
  snapshotId: snapshot.id
})
```

**Tab: Python (sync)**

```python
sandboxes.snapshots.delete(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)
```

**Tab: Python (async)**

```python
await sandboxes.snapshots.delete(
    sandbox_group_id=snapshot.sandbox_group_id,
    snapshot_id=snapshot.id,
)
```

You cannot delete a snapshot while its status is `creating`. Deletion prevents future restores and does not affect sandboxes already restored from the snapshot.

---

##### Appendix: Glossary definitions

###### compute plan

Specifies the CPU and RAM available to your service's *instances*.

Common compute plans for a new web service include:

- *`free`*: 0.1 CPU / 512 MB RAM
- *`0.5c-512mb`*: 0.5 CPU / 512 MB RAM
- *`1c-2g`*: 1 CPU / 2 GB RAM

Compute plans were previously known as *instance types*.

Related article: https://render.com/docs/compute-plans.md