Documentation

Snapshots

Sandboxes are persistent by default: stopping one saves its filesystem, and it resumes exactly where it left off.

What it is

When a persistent sandbox stops, Syva captures a snapshot of its filesystem as a compressed block delta against the base image and stores it durably. Resuming boots a fresh session from that snapshot — installed packages, cloned repos, and written files are all there.

Snapshots capture the filesystem, not memory. Running processes do not survive a stop; the sandbox start_command runs again on resume.

Stop and resume

Name a sandbox to make it a durable, reconnectable workspace. get_or_createresumes it when it exists and creates it when it does not.

TypeScript
// Persistent sandboxes (the default) snapshot their filesystem on stop.
const sandbox = await Sandbox.getOrCreate({
  name: "agent-workspace",
  image: "node-22:base",
});

await sandbox.runCommand("npm", ["install"]);

const stopped = await sandbox.stop();
console.log(stopped.lastSnapshot?.id, stopped.lastSnapshot?.sizeBytes);

// Later — even from another process — resume by name.
const resumed = await Sandbox.getByName("agent-workspace").then((s) => s.start());

A stopped sandbox bills no CPU or memory — only snapshot storage. Sandbox TTLs stop persistent sandboxes with a snapshot instead of destroying them, so an expired workspace is never lost. Deleting a sandbox removes its snapshots and frees its name.

Fork

Forking boots a new sandbox from another sandbox's latest snapshot. Prepare an environment once — dependencies installed, repo cloned, caches warm — then fan out identical copies in seconds.

TypeScript
// Fork: boot a new sandbox from another sandbox's latest snapshot.
const base = await Sandbox.getByName("agent-workspace");
const fork = await base.fork({ name: "experiment-1" });

// Or fork many rollouts from one prepared state:
const rollouts = await Promise.all(
  [1, 2, 3].map((n) => Sandbox.create({ sourceSandbox: "agent-workspace", name: `rollout-${n}` })),
);

Retention and billing

Snapshot storage is billed at $0.08 per GiB-month on the compressed delta — the bytes your sandbox actually changed, not the full disk. Every snapshot is kept until it expires: 30 days after its last use by default, with each resume or fork resetting the timer. Add a keep_last_snapshots policy to bound how many snapshots a sandbox keeps, and tune everything after creation with sandbox.update() — including rolling back to an older snapshot via current_snapshot_id.

TypeScript
// Default: every snapshot is kept until it expires (30 days after last use).
const sandbox = await Sandbox.create({
  image: "node-22:base",
  name: "tuned-retention",
  snapshotExpirationSeconds: 7 * 24 * 3600,      // expire 7 days after last use
  keepLastSnapshots: { count: 3 },               // bound storage to the 3 newest
});

// Tune later, or roll back to an older snapshot:
await sandbox.update({ keepLastSnapshots: { count: 1 } });
await sandbox.update({ currentSnapshotId: "snap_..." });

// Manual checkpoint with its own expiration (stops the sandbox):
const snapshot = await sandbox.snapshot({ expirationSeconds: 3600 });

// Ephemeral sandboxes skip snapshots entirely:
const scratch = await Sandbox.create({ image: "node-22:base", persistent: false });
  • keep_last_snapshots keeps the N newest snapshots (1–10). The object form adds expiration_seconds for the kept snapshots and delete_evicted=False to let evicted snapshots age out instead of deleting them immediately.
  • snapshot_expiration_seconds sets the TTL; 0 keeps snapshots until deleted.
  • sandbox.update(...) changes any of these later, and rolls back via current_snapshot_id.
  • persistent=False opts out entirely for one-off workloads.