Which one do I want?
Three things to do with a snapshot, and they get mixed up because they all come from the same one.- Resume gives you your sandbox back. Same Sandbox, same id, new machine underneath.
- Fork gives you a second sandbox holding a copy of the filesystem as it is right now. The original keeps running, untouched.
- Template freezes a named copy that stays put. You deploy from it whenever you like, and it still works long after the sandbox it came from is gone.
What is captured
Captured
/home/user: your code, files, and configDocker named volumes (/var/lib/docker/volumes)Your changes under /etc, /usr, /opt, /root, /srv, cron tables, and the apt package database: installed packages, systemd services, system configNot captured
The base OS and pre-installed tooling, which ship with the machine imageMachine identity: hostname, network config, SSH host keysRunning processes, memory, open portsDocker build cache, and images no container uses (
/var/lib/docker; named volumes and the containers you had running, with their images, do come back)sudo rm -rf /opt/kimi-code /usr/local/bin/kimi, sudo npm uninstall -g @openai/codex) or an apt package, and it stays gone on every resume, fork and template deploy. Your own installs always shadow the pre-installed copies.
Coming back from a snapshot behaves like rebooting a server. Your files, installed packages and system setup return, and systemd services you enabled start again on their own. Processes you ran by hand do not survive; restart them, or make them a service. Snap packages are recorded and reinstalled. See Long-Running Tasks.
Docker builds across resume and fork
Docker and BuildKit are installed, anddocker build uses the layer cache normally while a sandbox runs: a rebuild with nothing changed takes well under a second. That cache lives in /var/lib/docker, which is not captured, so the first build after a resume or on a fork starts from scratch and pulls its base images again. Containers you had running are recreated with the image they were using; only the build cache is lost.
To keep the cache, export it into your home directory, which is captured:
Excluding files with .boxignore
Build artifacts and dependency trees are worth nothing in a snapshot and slow every restore down. Nothing is left out of a snapshot unless you ask for it: write a .boxignore and every capture from the next one on obeys it.
.boxignore in a repo covers that repo and one in your home directory covers the whole sandbox. It is looked for up to six directories below your home directory, and the search skips node_modules, .next, target and vendor. Put the file at the root of the tree you want skipped, not inside it.
Your .gitignore is not used. It answers “do not commit this”, which is a different question from “it is safe to lose this on resume”, and a build cache is routinely both. It is also not yours at all in a tool you installed as a git clone: ~/.nvm’s own .gitignore excludes v*, which is every node version you have installed.
.git is always captured, since it is the one thing you cannot regenerate.
Sandboxes created before this file was renamed still honour the old .oneignore name.
Automatic snapshots
Snapshots are incremental: the first is a full base, each later one stores only what changed, compressed, content-addressed and deduped against the base image. They are taken every minute while the sandbox is ready or idle, and a final one when it stops. A snapshot does not reserve a second copy of your entire root disk. Capture uploads compressed chunks; restore extracts chunks onto a fresh machine and removes staging files as they are consumed. The machine restore budgets apply to the uncompressed data restored onto that machine, not the compressed download size. If that final snapshot fails, the stop is aborted and the machine keeps running, so stopping can never lose data. Stopping at any moment is safe; the snapshot is always complete. Snapshots are kept for the life of the sandbox. Its latest can be resumed or forked whether it stopped yesterday or months ago. Superseded ones are cleaned up continuously as new ones are taken.When a stop is refused
Stopping saves the disk first, and if that save is failing we refuse the stop and leave the sandbox running rather than throw away your work. We retry on our own and email you. Billing pauses by itself. The meter stops at the first refused attempt, in the balance you see as well as on your invoice. A Sandbox held open by a broken snapshot costs you nothing from that moment on, so there is nothing to claim and no refund to ask for. The pause lifts when you start using the sandbox again. If it keeps happening, snapshots are genuinely failing on that sandbox. We are alerted automatically, but contact us so we look at yours. To stop anyway and accept losing everything written since the last successful snapshot, pass--force.
Resume
Brings the same sandbox back on a fresh machine, from its latest snapshot. Same Sandbox id, same filesystem, new hardware.boat stop. Shrinking to a smaller machine is refused if the sandbox holds more data than it can take, and the sandbox is left untouched. See Machines.
Omit ttlSeconds to keep the sandbox’s current lifetime. Pass null (--no-auto-stop) to switch auto-stop off entirely.
Fork
Clones a sandbox from its latest snapshot into a new, independent sandbox. The source keeps running and is never modified.env. It also inherits the source’s exact environment version, so a fork never picks up configuration its source never had. See Environments.
A fork does not inherit the source’s lifetime. It defaults to 1 hour, so a fork of a sandbox with auto-stop switched off is not itself left running forever. Pass ttlSeconds (or --no-auto-stop) when you want something else.
Use fork for a throwaway copy right now: a second branch of work, a risky experiment, one machine per user of your product. If you find yourself forking the same sandbox repeatedly, make it a template instead.
Template Sandboxes
When many sandboxes need the same stack pre-installed, build it once, save it under a name, and deploy from that name instead of installing on every fresh sandbox.- Create a sandbox and install everything: runtimes, packages, your app or daemon.
- Save it:
boat snapshot <id> <name>. That freezes the sandbox’s disk at this moment under the name. - For each new Sandbox:
boat new --from <name>. Deploys are usable in a few seconds, at roughly constant cost regardless of how much the template holds.
from is a reserved word in Python, so build that one request with from_dict as above rather than keyword arguments.boat snapshots.
Templates are not environments
A template holds the disk. An environment holds the configuration. They are different tools and most setups use both.
If you would put it in a Dockerfile it belongs in a template; if you would put it in a
.env it belongs in an environment. Compose them:
Updating a template
Save the same name again: resume the sandbox (or any sandbox set up the way you want), update the stack, and runboat snapshot <id> <name> with the existing name. The name points at the new state and the old artifact is released. Sandboxes already deployed from it are unaffected. If a re-save fails, the name keeps deploying the last good save.
What happens on restore
A resume, fork or deploy is usable in a few seconds, whatever the sandbox holds. The full file tree is there immediately, every file is readable on demand, and content finishes downloading in the background. Permissions, ownership, timestamps and extended attributes come back with your files, and on directories too. Two details are worth knowing:- Extended attributes on a file become readable once that file’s content has arrived. Directories carry theirs from the moment the sandbox is up.
- Directory modification times are restored once the background download finishes rather than immediately, because writing a file into a directory updates that directory’s timestamp, so setting it any earlier would just be overwritten.
Warming for faster first boots
A Sandbox records the order in which files are first opened while it is starting up, and keeps that order in.ascii/playbook.json. On the next start those files are fetched first, so your app reaches a working state before the rest of the disk has arrived. The playbook is an ordinary file, so it is captured into the snapshot and every fork or deploy inherits it.
Recording only happens while a sandbox is starting up from a snapshot, so the order matters:
1
Start the sandbox from a snapshot
Resume a stopped sandbox, or deploy one from the template you are about to update. A Sandbox created from scratch has nothing to record against.
2
Boot your app straight away
Run the normal startup, right away, while the sandbox is still filling in. Every file it opens is recorded in the order it asks for them. Files opened later, once the sandbox has finished filling in, are not recorded.
3
Let it finish, then save
The playbook is written when the sandbox finishes filling in. Save after that, or the run you just did is not in the template.
Retention
By default, snapshots are kept for the life of the archived sandbox: its latest snapshot can be resumed or forked whether it stopped yesterday or months ago. Superseded snapshots are cleaned up continuously as new ones are taken. Permanent deletion is different from archive. Deleting a sandbox or snapshot returns a background operation and makes the target unavailable; it cannot be resumed. Named snapshots remain independent of their source sandbox. When you remove one, its backing data is scheduled no earlier than six hours later so already-issued signed upload URLs expire first. With zero data retention, archived sandbox data and named snapshots are queued for deletion instead of retained.Inspect and download
pull writes two subfolders, home_user/ (your /home/user) and docker/ (named volumes), reflecting exactly the files that were live at that snapshot. There is no SDK equivalent of pull: it is getSnapshotDownload plus local reassembly.
Browse the same tree, and download files from it, on the Snapshots tab of the dashboard.
See the Snapshots API for the full surface.
Deleting a sandbox’s snapshots
Stopping a sandbox keeps its snapshots, that is the whole point of stopping. Deleting a sandbox throws them away.X-Ascii-Confirm-Delete must equal the sandbox id exactly, or the request is refused with 409 and nothing is deleted. See Data retention and deletion for the operation you get back and how to poll it.
You can also delete a sandbox from the ⋯ menu on its row in the dashboard.
The Sandbox leaves your account immediately; the snapshot data goes once the machine has finished shutting down.
What survives, and why. Snapshots are shared: a fork, a resume and a deploy from a template all read the same physical objects as the sandbox they came from. Deleting a sandbox therefore only removes the snapshot data nothing else is using. Kept are:
- chains a sandbox forked or resumed from this one still restores from
- named snapshots saved from this sandbox, which are meant to outlive it. Delete those with
boat snapshot rm <name>when you want the bytes gone.