---
title: Snapshots
description: Capture a disk, restore onto it, fork a machine from it, or name it as a template.
---

Three things stand on one mechanism — capturing a machine's disk — and differ in what they are for.

|              | What it is                                 | Reach for it when                        |
| ------------ | ------------------------------------------ | ---------------------------------------- |
| **Snapshot** | a captured disk, belonging to one machine  | you want to be able to go back           |
| **Fork**     | a new machine from a copy of a disk        | you want to branch and run both          |
| **Template** | a named, organization-level starting state | you want every new machine to start here |

## What a capture holds

Files, installed software, and browser profile data — cookies, logins, extensions.

It holds **no RAM and no live process state**. Restoring boots the disk; it does not resume a
session. A process that was running is not running afterwards. That is a property of the substrate
rather than a setting, so there is nothing to turn on.

Design for it: write state to disk, not to a long-lived process.
[Secrets](/docs/sdk/secrets) are deliberately not carried by a capture.

## Snapshot

<CodeGroup>

```ts TypeScript
const snap = await machine.snapshot({ name: "after-setup" });
snap.state; // "ready" — this waited for the capture

const pending = await machine.snapshot({ name: "later", wait: false });
```

```python Python
snap = machine.snapshot(name="after-setup")
snap["state"]   # "ready" — this waited for the capture

pending = machine.snapshot(name="later", wait=False)
```

</CodeGroup>

The machine has to be **running** — a disk is captured from a live instance. The capture is
asynchronous on the server and the SDKs wait for it by default, so what you get back is
immediately restorable. `wait: false` gives you the pending record to poll yourself.

<CodeGroup>

```ts TypeScript
for await (const s of machine.snapshots()) console.log(s.id, s.state, s.origin);

await client.snapshots.waitUntilReady(pending.id);
await client.snapshots.get(snap.id);
await client.snapshots.delete(snap.id);
```

```python Python
for s in machine.snapshots():
    print(s["id"], s["state"], s["origin"])

client.snapshots.wait_until_ready(pending["id"])
client.snapshots.get(snap["id"])
client.snapshots.delete(snap["id"])
```

</CodeGroup>

`origin` is `manual` (you asked), `stop` (taken automatically when the machine stopped) or
`template` (the capture behind a template).

**Only the newest capture of a machine can be deleted.** Captures form a chain in the order they
were taken, so removing an older one raises a `conflict` naming the snapshot in the way. Delete
forward; there is no flag to override it.

## Restore

<CodeGroup>

```ts TypeScript
await machine.restore(snap.id);
```

```python Python
machine.restore(snap["id"])
```

</CodeGroup>

The current disk is captured first, under the name "Before restore", so the state being replaced
stays recoverable. The machine then restarts: a running one comes back running, a stopped one boots
into the restored disk next time it starts.

Anything open on the machine is disconnected, and **nobody may be holding the input lease** — the
SDKs release theirs first.

## Fork

<CodeGroup>

```ts TypeScript
const branch = await machine.fork({ name: "branch-a" });
await branch.waitForDesktop();
```

```python Python
branch = machine.fork(name="branch-a")
branch.wait_for_desktop()
```

</CodeGroup>

Without a snapshot id the current disk is captured first, which needs the machine running. With
one, the fork stands on bytes that already exist — which is how you fan out several machines from a
single capture without paying for the capture each time:

<CodeGroup>

```ts TypeScript
const base = await machine.snapshot({ name: "configured" });
const workers = await Promise.all(
  ["a", "b", "c"].map((n) => machine.fork({ snapshotId: base.id, name: `worker-${n}` })),
);
```

```python Python
base = machine.snapshot(name="configured")
workers = [
    machine.fork(snapshot_id=base["id"], name=f"worker-{n}")
    for n in ("a", "b", "c")
]
```

</CodeGroup>

A fork comes back in `creating`, exactly like a create, so `waitForDesktop` is what waits for a
usable computer. Afterwards it owes the original nothing: deleting the parent leaves every fork
running.

## Templates

<CodeGroup>

```ts TypeScript
const tpl = await machine.saveAsTemplate({ name: "research-box" });
const fresh = await client.machines.create({ template: tpl.id, size: "standard" });

for await (const t of client.templates.list()) console.log(t.name, t.state);
await client.templates.delete(tpl.id);
```

```python Python
tpl = machine.save_as_template(name="research-box")
fresh = client.machines.create(template=tpl["id"], size="standard")

for t in client.templates.list():
    print(t["name"], t["state"])
client.templates.delete(tpl["id"])
```

</CodeGroup>

A template is a snapshot with a name on it and an organization behind it — how a team agrees on
what its standard box is. `saveAsTemplate` needs the machine running and waits for the capture, so
what comes back is a template `machines.create` will accept.

`client.templates.create` also takes a `snapshotId`, or neither — a named image and size with no
captured disk behind it.

Deleting a template leaves machines created from it running and keeps their disks: a machine copies
the template's bytes when it is created and owes it nothing afterwards.

:::note
A captured disk currently lives on one host, so a snapshot is not portable across hosts in this
version.
:::
