Solari

Snapshots

A snapshot saves the exact state of a running machine so you can come back to it later. Use one to rewind a machine to how it was, or to start a brand-new machine that opens straight into that saved state.

Snapshots work the same way for both VMs and sandboxes. They save you from repeating slow setup: prepare a machine once, install and configure everything, take a snapshot, then spin up as many ready-to-go copies as you need.

Take a snapshot

snapshot(name?) saves the machine's current state and gives you back a snapshot id. The machine keeps running the whole time, so you can save a checkpoint without interrupting your work.

The machine must be running
snapshot() and revert() both operate on a running machine — a paused machine has no live VM to checkpoint or swap, so both return 409 NotRunning. Call resume() first. (A paused machine's state is already saved — that is what pause does.)
const sbx = await sandboxes.create({ template: "base" })
await sbx.connect()

// Do some slow, one-time setup.
await sbx.commands.run("sh", {
  args: ["-c", "apt-get update && apt-get install -y build-essential"],
  onStdout: (d) => process.stdout.write(d),
})
await sbx.files.write("/opt/app/config.json", "{ ...}")

// Save this state. The sandbox stays running.
const snapId = await sbx.snapshot("after-setup")
console.log("snapshot:", snapId)

Rewind a machine

revert(snapshotId) rewinds the same machine back to a snapshot. Its id doesn't change, so anything that points at it keeps working. Handy for resetting to a clean starting point between test runs.

await sbx.revert(snapId) // same sandboxId, state rewound

Under the hood a revert boots a fresh VM from the snapshot and swaps it in behind the same id, so open connect() / stream connections drop and re-establish (the machine's whole RAM and disk just changed — anything connected is looking at the old world anyway). You can revert to any snapshot you own, not just ones taken from this machine. If a revert fails, the machine is left untouched and keeps running — just retry.

Start a new machine from a snapshot

Pass fromSnapshot to create to start a fresh machine from a snapshot. Each copy is fully independent, so you can run many at once from one prepared starting point.

// Start 5 ready-to-go workers from the same prepared snapshot.
const workers = await Promise.all(
  Array.from({ length: 5 }, () =>
    sandboxes.create({ template: "base", fromSnapshot: snapId }),
  ),
)

A machine started with fromSnapshot is a full machine: you can snapshot it again, revert it, pause it, and fork from its snapshots — lineages can branch anywhere, not only from the original machine. Machines created from a snapshot inherit the snapshot's memory topology, so if the source machine ran with extra RAM (say memMb: 4096), pass the same memMb when forking.

Delete a snapshot

Every snapshot is self-contained — it carries its own complete disk and memory image, and never references a parent snapshot's storage. So you can delete any snapshot at any time, ancestors of a lineage included, except while something is actively using it:

  • a machine started fromSnapshot is still running or paused (409 SnapshotHasChildren), or
  • the snapshot was promoted to a template that still exists (409 SnapshotBacksTemplate — delete the template first).

Deleting a snapshot erases its stored bytes immediately — the id and the data are gone for good.

Storage pricing

From October 1, 2026, stored snapshots bill at $0.05 per GB-month, pro-rated daily, from your organization's credit balance. The first 10 GB across your organization are free — only the excess bills. Snapshots you promote to templates count toward the total; Solari's built-in templates don't. Nothing is charged for storage held before that date. See pricing for the full rate card.

Because every snapshot is self-contained, the easiest way to trim your bill is to delete the snapshots you no longer need — including superseded ancestors in a lineage (see "Delete a snapshot" above). A deleted snapshot stops accruing charges the same day. If your balance reaches zero, taking new snapshots is paused until you top up; restoring, forking, and deleting existing snapshots always keep working.

VMs work the same way
The same snapshot() / revert() methods and fromSnapshot option work on VMs: save a VM with your apps open and signed in, then start ready-to-go copies of it.

Snapshot vs. pause

Both save your state, but they're for different things:

  • Snapshot: a named save point you can rewind to or start new copies from later, while the machine keeps running.
  • Pause (Stop in the console): parks the machine and saves its state. A paused machine won't be shut down for being idle, and it picks up right where it left off the next time you connect().
await sbx.pause()                    // park it; picks up where it left off
await sbx.resume()                   // wake the paused sandbox back up