Isorun Docs
Sandboxes

Checkpoints & Rollback

Capture sandbox state, restore quickly, and fork prepared runtimes for parallel work.

A checkpoint captures a sandbox's full state so you can restore it later or fork it into parallel copies.

Use checkpoints when setup is expensive and you want repeatable branching.

Snapshot and restore

TypeScript
import { Isorun } from 'isorun'

const isorun = new Isorun()
const sandbox = await isorun.create({ image: 'python:3.12-slim' })
await sandbox.exec('pip install numpy pandas')
const snap = await sandbox.snapshot()
await sandbox.destroy()

// Later, anywhere in the same region:
const restored = await isorun.restore(snap.id)
try {
  const r = await restored.exec("python3 -c 'import numpy; print(numpy.__version__)'")
  console.log(r.stdout.trim())
} finally {
  await restored.destroy()
}

Fork for parallel hypotheses

Prepare once, then fork multiple children for concurrent experiments.

TypeScript
const parent = await isorun.create({ image: 'python:3.12-slim' })
await parent.exec('pip install transformers torch')
const children = await parent.fork(5)

try {
  await Promise.all(
    children.map((child, i) => child.exec(`python3 evaluate.py --variant=${i}`))
  )
} finally {
  await Promise.all(children.map((c) => c.destroy()))
  await parent.destroy()
}

What carries over

  • Filesystem state at fork/snapshot time.
  • Loaded runtime state (so setup usually does not need to re-run).
  • Environment configuration applied before checkpoint/fork.

What resets

  • Active outbound network sessions.
  • In-flight operations at the time of checkpoint/fork.
  • Per-sandbox runtime control channel.

Roll back to a snapshot

TypeScript
const sandbox = await isorun.create({ image: 'python:3.12-slim' })
try {
  await sandbox.exec("echo 'state-ok' > /tmp/state.txt")
  const snap = await sandbox.snapshot()

  const failed = await sandbox.exec('rm /tmp/state.txt && exit 1')
  if (failed.exitCode !== 0) {
    await sandbox.destroy()
    const rolled = await isorun.restore(snap.id)
    const r = await rolled.exec('cat /tmp/state.txt')
    console.log(r.stdout.trim())
    await rolled.destroy()
  }
} finally {
  // sandbox may already be destroyed above; destroy() throws on a destroyed
  // sandbox, so guard for production code.
}

destroy() throws if the sandbox is already destroyed. When a code path may destroy a sandbox before the finally block runs, guard the cleanup call.

Operational checklist

  • Store snapshot IDs alongside job metadata.
  • Destroy restored/forked children in finally paths.
  • Set explicit exec() timeouts in child runs.
  • Call isorun.deleteSnapshot(id) when a snapshot is no longer needed.

Next steps

On this page