Snapshot and restore a Box
Take a disk snapshot of a stopped Cubicle Box, list its snapshots, restore the Box in place, and create a new Box from a snapshot with its own size, using the TypeScript SDK, the CLI or the HTTP API.
A snapshot is a copy of a stopped Box's whole disk: the operating system, installed software and every home directory, but no memory or running processes. Take one before a risky change so you can roll the Box back, or use one as a template for new Boxes. Snapshots are stored on the Box's Node and are deleted with their Box. Snapshots explains the rules.
Before you begin
- Set up the SDK or the CLI as in the Quickstart. The examples use a Box
acme/job-1(cubicle boxes create --org acme job-1 --wait). TypeScript snippets useconst cubicle = new Cubicle()andconst box = cubicle.boxes.ref("acme/job-1"), and curl snippets read awritekey fromCB_SDK_API_KEYand usejq. - You need a grant on the Box, or the owner or admin role in its organization. An API key needs
writescope to take or restore a snapshot.
Take a snapshot
Stop the Box first: if its desired state is not stopped, the request fails with 409 conflict "stop the box before taking a snapshot". A hibernated Box counts as not stopped, so stop it too, which discards its saved memory. Then wait until it has finished stopping (state is stopped at the current desired.generation), or the snapshot operation can fail with "box must be stopped". The SDK's stop() and the CLI's --wait wait for this (requirements).
Snapshot names use lowercase letters, digits, ., _ and -, start with a letter or digit, and are at most 63 characters. Names need not be unique, so refer to a snapshot by its ID.
await box.stop() // waits until the Box is stopped
const snapshot = await box.snapshot("before-upgrade") // waits until the snapshot is complete
console.log(snapshot)
// => { id: "3f2a9b1c-7d4e-4a5f-8b6c-1e2d3f4a5b6c", name: "before-upgrade", status: "complete", operationId: "…",
// createdAt: "2026-11-05T10:04:12.000Z", completedAt: "2026-11-05T10:04:40.000Z" }snapshot waits up to 15 minutes by default. Pass { timeoutMs } to change that.
In the Dashboard, open the Box and use Create snapshot on its Snapshots tab.
List snapshots
const snapshots = await box.listSnapshots() // newest first
// => [{ id: "3f2a9b1c-7d4e-4a5f-8b6c-1e2d3f4a5b6c", name: "before-upgrade", status: "complete", … }]A snapshot's status is pending until its operation finishes, then complete, ready to restore or create Boxes from, or failed, with the reason in the operation's error (status). Any member of the organization can list a Box's snapshots. To find snapshots across the organization that you may create Boxes from, use cubicle.listSnapshots() in the SDK or GET /v1/orgs/acme/snapshots; the CLI has no command for this list.
Restore a Box in place
Restoring replaces the Box's whole disk with one of its own complete snapshots, so everything written to the disk since then is lost. Take another snapshot first if you may need it. The Box must be fully stopped, as for taking a snapshot, and stays stopped afterwards: start it when the restore is done. It keeps its ID, name, private IP address and grants, and a restore cannot bring back revoked access (what a restore changes).
const snapshot = (await box.listSnapshots()).find(
(candidate) => candidate.name === "before-upgrade" && candidate.status === "complete",
)
if (!snapshot) throw new Error("no complete before-upgrade snapshot")
await box.stop()
await box.restore(snapshot.id) // waits until the restore is done
await box.start() // waits until the Box is readyIn the Dashboard, use Restore next to the snapshot on the Box's Snapshots tab.
Check a restore
This round trip writes a file, snapshots the Box, changes the file, restores and reads it back:
await box.exec(["sh", "-c", "echo before > state.txt"])
await box.stop()
const snapshot = await box.snapshot("before-upgrade")
await box.start()
await box.exec(["sh", "-c", "echo after > state.txt"])
await box.stop()
await box.restore(snapshot.id)
await box.start()
const check = await box.exec(["cat", "state.txt"])
console.log(check.stdout) // => "before\n"Create a Box from a snapshot
A new Box created from a snapshot starts with a copy of that disk, and the source Box can keep running. The snapshot must be complete, its source Box must still exist, and the new Box goes in the same organization. You need a grant on the source Box, or the owner or admin role. Do not pass a base image: the new Box uses the source Box's.
The new Box is placed on the Node that holds the snapshot. If that Node is unavailable or full, the request fails with 503 capacity. Its vCPUs, memory and disk default to the source Box's. You can set any allowed size, but diskGiB must be at least the source Box's disk: a disk can grow but not shrink (size rules).
In the CLI and curl examples, replace SNAPSHOT_ID with the snapshot's ID from List snapshots.
const snapshot = (await box.listSnapshots()).find(
(candidate) => candidate.name === "before-upgrade" && candidate.status === "complete",
)
if (!snapshot) throw new Error("no complete before-upgrade snapshot")
// Waits until the new Box is ready, unless you pass start: false.
const clone = await cubicle.boxes.create({ name: "job-2", snapshotId: snapshot.id, diskGiB: 24 })
console.log(clone.name, clone.id) // => job-2 6a1f0c3e-2b4d-4e8f-9a7c-5d3e1f2b4a6cIn the Dashboard, choose the snapshot under Image when you create a Box.
The new Box gets its own ID, name, private IP address, SSH host key and hostname box-job-2, and a grant for you only: grant other people access separately (what it gets).
The new Box's disk holds every home directory from the source Box. Other people's accounts are
locked in it, but anyone with sudo in the new Box can read their files.
Keep or remove snapshots
You cannot delete a single snapshot: deleting a Box deletes all of its snapshots. To keep a snapshot's contents after you delete its Box, create a Box from it first (retention).
Troubleshooting
409 conflict"stop the box before taking a snapshot" or "stop the box before restoring a snapshot": the Box's desired state is notstopped. Stop it and wait until it is stopped.- Operation
failedwith "box must be stopped": the request reached the Node before the Box finished stopping. Wait forstate: stoppedat the current generation, then try again. 409 conflict"a snapshot or restore is in progress for this box": wait for the snapshot or restore operation to finish before you start, stop, hibernate or delete the Box.404 not_found"snapshot not found" on a restore: the snapshot belongs to another Box. You can only restore a Box from its own snapshots; create a Box from it instead.404 not_found"snapshot not found" on a create: the snapshot is in another organization, or its source Box was deleted.409 conflict"snapshot is not complete": wait until its status iscomplete. Afailedsnapshot cannot be used.400 invalid_request"disk must be at least N GiB (the snapshot's size)": raisediskGiB, or leave it out to use the source Box's size.400 invalid_request"choose a base image or a snapshot, not both": removebaseImage. The CLI says "choose --base or --snapshot, not both".503 capacity"the node holding this snapshot is unavailable" or "the node holding this snapshot has no capacity for this box": the new Box can only run on that Node. Try again later, or ask for a smaller size.409 conflict"box job-2 is still being created from a snapshot of this box" on a delete: wait until the new Box has leftprovisioning, then delete the source.403 forbidden"box grant or organization admin role required": ask an owner or admin for a grant on the Box.
Related
- Snapshots: what a snapshot captures and where it lives.
- Stop, hibernate and wake a Box: why a hibernated Box must be stopped before a snapshot.
- Box lifecycle: states, generations and readiness.
- Waiting: how the SDK's waits and timeouts work.
cubicle snapshot,cubicle snapshotsandcubicle restore: the CLI reference.- Take a snapshot, Restore a Box and Create a Box: the API reference.
Use the desktop console
Open a Box's graphical desktop from the Cubicle Dashboard in a full-screen VNC console, or from a native VNC client on port 5900 over the private network, and understand console readiness, clipboard, keyboard and session limits.
Build a template Box
Build a reusable Cubicle template Box instead of a custom image, by installing software over SSH, stopping and snapshotting the Box, and creating new Boxes from the snapshot with the TypeScript SDK, the CLI or the HTTP API, with the Node, capacity, grant and copied-data caveats.

