---
title: Snapshots, forks and templates
description: Captured disks, branched machines, and named starting states.
---

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, and a file that was open is
closed. `includes_memory` is `false` on every snapshot, and it is a property of the substrate
rather than a setting, so there is nothing to turn on.

Design for that. Write state to disk, not to a long-lived process.

[Secrets](/docs/reference/secrets) are delivered to tmpfs and are deliberately **not** carried by
a capture.

## Snapshots

```
POST   /v1/snapshots                        capture a machine's disk
GET    /v1/snapshots                        list, filterable by machine and origin
GET    /v1/snapshots/{snapshot_id}
DELETE /v1/snapshots/{snapshot_id}
POST   /v1/machines/{machine_id}/restore    put a machine back onto one
```

```ts
const snap = await machine.snapshot({ name: "after-setup" });
```

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

States are `pending`, `ready`, `error` and `deleting`. `origin` says how it came about:

- `manual` — you asked for it
- `stop` — taken automatically when the machine stopped
- `template` — the capture behind a template

### Deleting is newest-first

Captures of one machine form a chain in the order they were taken, and **only the newest can be
deleted**. Removing an older one is refused with a `conflict` naming the snapshot in the way.
That is a consequence of how the chain is stored, not a policy, so there is no flag to override
it — delete forward.

### Restoring

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

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 is started. Anything open on the machine is
disconnected, and nobody may be holding the input lease when you call it — the SDKs release
theirs first.

## Forks

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

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:

```ts
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}` })),
);
```

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

```
GET    /v1/templates
POST   /v1/templates
GET    /v1/templates/{template_id}
DELETE /v1/templates/{template_id}
```

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.

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

`saveAsTemplate` is the usual way to make one, because a template almost always begins as a
machine somebody set up by hand. `client.templates.create` also accepts a `snapshotId` — standing
on bytes that already exist — or neither, which makes it a named image and size with no captured
disk behind it.

States are `building`, `ready` and `error`. Creating from a template pins the image; the size is
still the create call's to choose.

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.

## Quotas and cost

Snapshots per machine and templates per organization are plan entitlements. Captured disk counts
toward storage, metered in byte-seconds and billed per GB-month. See
[billing](/docs/reference/billing).

:::note
A captured disk currently lives on one host. Object storage is declared in configuration but
nothing writes to it yet, so a snapshot is not portable across hosts in this version.
:::
