Snapshots
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 are deliberately not carried by a capture.
Snapshot
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 });snap = machine.snapshot(name="after-setup")
snap["state"] # "ready" — this waited for the capture
pending = machine.snapshot(name="later", wait=False)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.
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);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"])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
await machine.restore(snap.id);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 starts.
Anything open on the machine is disconnected, and nobody may be holding the input lease — the SDKs release theirs first.
Fork
const branch = await machine.fork({ name: "branch-a" });
await branch.waitForDesktop();branch = machine.fork(name="branch-a")
branch.wait_for_desktop()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:
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}` })),
);base = machine.snapshot(name="configured")
workers = [
machine.fork(snapshot_id=base["id"], name=f"worker-{n}")
for n in ("a", "b", "c")
]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
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);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"])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.