Docs · Sandboxes

Snapshots & forks

A snapshot is a copy of the sandbox's whole disk.

  • Automatic snapshots are taken every hour while a sandbox runs, and when it stops. The 3 most recent are kept. They're free.
  • Saved snapshots are kept until you delete them: froog snapshot my-box --name before-upgrade.
$ froog snapshots my-box                        # list
$ froog fork my-box@before-upgrade my-box-2     # new sandbox from a snapshot
$ froog fork my-box try --count 5               # try-1 … try-5
$ froog restore my-box@before-upgrade           # roll back in place

On the dashboard, Snapshots on a sandbox shows its snapshots on a timeline and the sandboxes forked from them. Pick one to restore to it, fork it or copy its command. In the API, a sandbox forked or started from a saved snapshot has forked_from: the source sandbox's name, the snapshot's id and name, and when it was copied.

Saved snapshots as templates

A saved snapshot belongs to your account, not just its sandbox: install your stack once, save it under a name, then start as many sandboxes from it as you like. It stays when its sandbox is deleted.

$ froog snapshot my-box --name web-stack     # save the disk under a name
$ froog new app-1 --from web-stack           # a new sandbox with that disk (and its OS and size, unless --size)
$ froog new app --from web-stack --count 5   # app-1 … app-5
$ froog snapshots                            # your saved snapshots
$ froog snapshots --rm web-stack             # remove it
$ froog snapshots --all                      # every snapshot of every sandbox
$ froog snapshot my-box --delete-auto        # delete its automatic snapshots
  • Names are unique in your account. Saving a name again replaces it once the new copy is ready (in an organization, only its creator's sandboxes or an owner or admin may: 403 saved_snapshot_name_taken). Sandboxes already started from it don't change. To keep the old one too, save under a new name (web-stack-v2).
  • A sandbox from a saved snapshot gets your environment (unless --no-environment), not the source sandbox's settings.
  • Saving a running sandbox snapshots its disk now, in the background (status goes from creating to available), and a stopped one saves its last snapshot.
  • The first 10 saved snapshots are included. Each one past that is $0.056 a day, from the wallet: with an empty wallet, a new one fails with 402 credit_required. froog snapshots and froog limits show how many you keep.

Share a saved snapshot with another account

A share code lets any froog account start sandboxes from one of your saved snapshots, without access to your account.

$ froog snapshot share web-stack              # prints the code once: fsh_…
$ froog snapshot shares web-stack             # its codes: uses, last use, active or revoked
$ froog snapshot unshare web-stack shr_…      # revoke one
$ froog new app --from fsh_…                  # the other account (or --from-share fsh_…)
  • froog keeps only a hash of the code. Lost it? Revoke it and make a new one. Up to 20 live codes per saved snapshot.
  • A code stays with the sandbox the name was saved from when you made it. It starts the newest copy of the name from that sandbox: saving web-stack again from it changes what the code gives. Saving web-stack from another sandbox revokes the name's codes (make a new one to share that disk). Removing the saved snapshot revokes its codes, and so does unshare. A revoked or unknown code gets 404 share_code_invalid.
  • The other account gets a copy of the disk as a saved snapshot of its own, under the same name (or web-stack-2 when it has one), marked shared, with the code's id as its source. That copy is theirs: it stays after you revoke the code or delete yours, and it counts and bills as one of their saved snapshots. Their sandbox bills their account and gets none of your variables. They can't share it on.
  • Their sandbox starts without their own environment too (as with --no-environment): the disk was prepared by another account, and anything on it (a startup script, a changed shell profile) would see their keys and files. froog new app --from fsh_… --environment NAME (API: "environment": true) opts in. Only do that for a disk you trust. The same goes for later sandboxes from their copy (--from web-stack).
  • Before their sandbox counts as running, froog removes your logins from its disk (the list), plus your environments' secret files and the repos they clone, and discards the freed space. Everything else on the disk is shared, so don't keep secrets in other files. Browsing or pulling their copy (possible before it ever boots) leaves the same paths out, and also all of ~/.ssh, ~/.claude.json, ~/.gitconfig, ~/.froog/env, the same paths under /root, /var/lib/cloud/instances and /var/log/cloud-init*.
  • Over the API: POST /saved-snapshots/{name}/shares (needs snapshot.write), GET the same path, DELETE /saved-snapshots/{name}/shares/{id}. Starting from a code is POST /sandboxes {"from": "fsh_…"} and needs snapshot.write (it saves the copy).

Look inside a snapshot

List and download files from any snapshot without starting anything: the sandbox can be stopped, or deleted for a saved snapshot.

$ froog snapshot ls web-stack                    # a saved snapshot's ~
$ froog snapshot ls my-box@latest app/src        # a sandbox's newest snapshot; relative paths are under ~
$ froog snapshot pull my-box@latest              # all of ~ into ./my-box-latest
$ froog snapshot pull web-stack ~/app -o ./app   # one folder
$ froog snapshot pull my-box@before-upgrade /etc/nginx/nginx.conf
  • A snapshot is a saved snapshot's name, or SANDBOX@SNAPSHOT (an id, a label, or latest). Paths default to ~ (/home/user). Absolute paths reach the whole disk.
  • pull writes a file as is, and a folder's contents into the -o directory. It skips symbolic links that point outside it (absolute, or with ..) and says how many.
  • API: GET /sandboxes/{name}/snapshots/{snap}/files?path=P and GET /saved-snapshots/{name}/files?path=P answer like GET /sandboxes/{name}/files ({path, kind, size, modified, entries}). …/files/download?path=P streams a file's bytes, or a folder as a tar whose entries are named from / (home/user/app/…). X-Froog-Entry-Kind says file or dir. A key needs snapshot.read and file.read.
  • On our hosts, froog mounts the disk read-only for the request, and never follows links inside it. It takes a few seconds before the first byte. Only ext4 and XFS disks can be looked inside (all of froog's images but Omarchy, whose disk is btrfs): others answer 501 not_supported (can't look inside a "btrfs" filesystem).

A stopped sandbox keeps its disk for 14 days. After that its automatic snapshots are deleted, and start and fork fail with snapshot_data_expired. To keep a disk longer, save a snapshot before then (froog snapshot my-box --name keep): saved snapshots never expire, and froog restore my-box@keep brings the sandbox back from one. froog list --json and the dashboard show each stopped sandbox's disk_expires_at.

Warm resume. For 10 minutes after a stop, the sandbox's VM is kept paused with its memory: an froog start in that window resumes it in about a second, with every program still running, the same address, and background commands carrying on. The stop still snapshots the disk and billing stops as usual. After 10 minutes, or if the host needs the memory, the paused VM goes and a start boots from the snapshot (as below). froog info and the API's warm_until say until when. Meanwhile, commands and background jobs that were running show as paused in froog history and froog jobs. A resume sets them running again, a fresh boot lost. A start at another size, a restore, or a host restart also boot from the snapshot. Don't count on warm resume for anything that must survive: save state to disk.

restore snapshots the current state first, so a restore can itself be undone. froog stop snapshots the disk and deletes the VM, and froog start brings it back from that snapshot: the disk is identical, but its SSH address (IP or port) can change.

A snapshot on a full host. A snapshot lives on the host its sandbox ran on. When a start, fork or new --from needs it and that host has no room (or is being emptied for maintenance), froog copies the disk to the host with the most room and starts the sandbox there, instead of failing. That adds the copy's time to the start (the disk goes from host to host compressed, holes skipped, so what counts is the space it uses). Meanwhile the sandbox stays starting (or creating), and progress in froog info and the API says copying its disk from host … to host …. A copy gives up after 2 hours. When no host has room, the start fails as before (no free capacity).

Snapshots copy the full disk, so they take time: in our tests about 35 seconds for a 3 GB disk, longer as the disk fills. Forks and starts take about 20–30 seconds. Stopping takes about 2 minutes.

Start times

froog times every sandbox that comes up, from the API call to the moment it accepts SSH (when the CLI, the dashboard and the API report it running). The status page publishes the median and the 95th percentile for the last 7 days (API: start_times in GET /v1/status, no key needed). These are our targets for the 95th percentile (measured on November 12, 2026: about 16 seconds to create, 18 to start, 20 to fork, and under a second for a warm resume):

WhatTarget (95th percentile)What it includes
New sandbox (create)45 sA VM from the base image or a saved snapshot, boot, SSH, environment variables
Start a stopped sandbox (start)45 sA VM from its last snapshot, boot, SSH
Warm resume (resume)3 sA start within 10 minutes of the stop: unpausing the VM it kept
Fork (fork)60 sA snapshot of the running source, then a VM from it

Not included: a disk copied from a full host (above), which adds the copy, and the setup your environment runs after boot (repos, setup scripts), which runs once the sandbox is already running. A start that fails isn't counted. It shows as error and in your alerts.