> ## Documentation Index
> Fetch the complete documentation index at: https://upstash.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Snapshots

Snapshots let you capture and duplicate box state. Use **snapshots** to save a point-in-time checkpoint you can restore later.

***

## What's included

A snapshot captures:

* **Filesystem**: the full disk state of the box at the time of the snapshot.
* **Agent configuration**: the agent harness, model, and API key settings.

A snapshot does not carry active schedules over to the new box.

<Note>
  Snapshots are the best way to preserve cloned repositories, installed dependencies, and prepared workspaces. If your box already has a repo checked out, restoring from a snapshot is usually faster than cloning it again.
</Note>

***

## API

### Create a snapshot

Call `snapshot()` on a running or paused box. The returned `Snapshot` object contains the ID you need to restore later.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  const snapshot = await box.snapshot({ name: "after-setup" })

  console.log(snapshot)
  // {
  //   id: "snap_x7f...",
  //   name: "after-setup",
  //   boxId: "box_abc123",
  //   sizeBytes: 52428800,
  //   createdAt: "2026-02-23T..."
  // }
  ```

  ```python box.py theme={"system"}
  snapshot = box.snapshot(name="after-setup")

  print(snapshot)
  # Snapshot(
  #   id="snap_x7f...",
  #   name="after-setup",
  #   box_id="box_abc123",
  #   size_bytes=52428800,
  #   status="ready",
  #   created_at=1771845600,
  # )
  ```
</CodeGroup>

<Note>
  Snapshots are independent of the source box. Deleting the original box does not delete its snapshots. They remain available for restore at any time.
</Note>

***

### List snapshots

Retrieve all snapshots belonging to a box.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  const snapshots = await box.listSnapshots()

  console.log(snapshots)
  // [
  //   { id: "snap_x7f...", name: "after-setup", status: "ready", ... },
  //   { id: "snap_a3b...", name: "pre-refactor", status: "ready", ... },
  // ]
  ```

  ```python box.py theme={"system"}
  snapshots = box.list_snapshots()

  print(snapshots)
  # [
  #   Snapshot(id="snap_x7f...", name="after-setup", status="ready", ...),
  #   Snapshot(id="snap_a3b...", name="pre-refactor", status="ready", ...),
  # ]
  ```
</CodeGroup>

***

### Delete a snapshot

Remove a snapshot by ID.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  await box.deleteSnapshot("snap_x7f...")
  ```

  ```python box.py theme={"system"}
  box.delete_snapshot("snap_x7f...")
  ```
</CodeGroup>

***

### Restore from a snapshot

`Box.fromSnapshot()` provisions a new box with the exact state from the snapshot. The original box is unaffected. You can branch into multiple boxes from the same checkpoint.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  const restored = await Box.fromSnapshot(snapshot.id)

  // Box.fromSnapshot accepts creation options such as name:
  const named = await Box.fromSnapshot(snapshot.id, { name: "restored-worker" })

  const files = await restored.files.list("/work")
  console.log(files)
  ```

  ```python box.py theme={"system"}
  restored = Box.from_snapshot(snapshot.id)

  # Box.from_snapshot accepts creation options such as name:
  named = Box.from_snapshot(snapshot.id, name="restored-worker")

  files = restored.files.list("/work")
  print(files)
  ```
</CodeGroup>

The restored box starts with the same workspace state from the snapshot. You can also configure lifecycle settings such as keep-alive and init commands on the restored box.

***

## Examples

### Checkpoint before risky operations

Snapshot your working state, then let the agent attempt a large refactor. If the result is bad, we restore the original state and try a different prompt.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const box = await Box.create({
    runtime: "node",
    agent: { harness: Agent.ClaudeCode, model: "anthropic/claude-opus-4-6", apiKey: process.env.ANTHROPIC_API_KEY },
    git: { token: process.env.GITHUB_TOKEN },
  })

  await box.git.clone({ repo: "github.com/my-org/my-repo" })
  const checkpoint = await box.snapshot({ name: "pre-refactor" })

  const run = await box.agent.run({
    // 👇 Potentially difficult task
    prompt: "Rewrite the database layer to use connection pooling",
  })

  if (run.status === "failed") {
    const fallback = await Box.fromSnapshot(checkpoint.id)
    await fallback.agent.run({
      prompt: "Add connection pooling to the existing database layer without rewriting it",
    })
  }
  ```

  ```python box.py theme={"system"}
  import os
  from upstash_box import Box, Agent

  box = Box.create(
      runtime="node",
      agent={"harness": Agent.CLAUDE_CODE, "model": "anthropic/claude-opus-4-6", "api_key": os.environ["ANTHROPIC_API_KEY"]},
      git={"token": os.environ["GITHUB_TOKEN"]},
  )

  box.git.clone(repo="github.com/my-org/my-repo")
  checkpoint = box.snapshot(name="pre-refactor")

  run = box.agent.run(
      # 👇 Potentially difficult task
      prompt="Rewrite the database layer to use connection pooling",
  )

  if run.status == "failed":
      fallback = Box.from_snapshot(checkpoint.id)
      fallback.agent.run(
          prompt="Add connection pooling to the existing database layer without rewriting it",
      )
  ```
</CodeGroup>

### Reusable base environments

Install dependencies once, snapshot, then spawn boxes from the snapshot to skip setup time.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const base = await Box.create({ runtime: "node" })
  await base.exec.command("npm install -g typescript eslint prettier")
  const baseSnap = await base.snapshot({ name: "node-toolchain" })
  await base.delete()

  const boxes = await Promise.all(
    tasks.map(async (task) => {
      const box = await Box.fromSnapshot(baseSnap.id)
      await box.agent.run({ prompt: task })
      return box
    })
  )
  ```

  ```python box.py theme={"system"}
  import asyncio
  from upstash_box import AsyncBox

  async def main() -> None:
      base = await AsyncBox.create(runtime="node")
      await base.exec.command("npm install -g typescript eslint prettier")
      base_snap = await base.snapshot(name="node-toolchain")
      await base.delete()

      async def run_task(task: str) -> AsyncBox:
          box = await AsyncBox.from_snapshot(base_snap.id)
          await box.agent.run(prompt=task)
          return box

      # spawn boxes from the snapshot in parallel
      await asyncio.gather(*(run_task(t) for t in tasks))

  asyncio.run(main())
  ```
</CodeGroup>

### Fan-out from a single state

Clone a repo once, snapshot, then run different agents or prompts in parallel from the same starting point.

<CodeGroup>
  ```typescript box.ts theme={"system"}
  import { Agent, Box } from "@upstash/box"

  const seed = await Box.create({
    runtime: "node",
    git: { token: process.env.GITHUB_TOKEN },
  })
  await seed.git.clone({ repo: "github.com/your-org/monorepo" })
  const snap = await seed.snapshot({ name: "repo-cloned" })
  await seed.delete()

  const [security, performance, docs] = await Promise.all([
    Box.fromSnapshot(snap.id),
    Box.fromSnapshot(snap.id),
    Box.fromSnapshot(snap.id),
  ])

  await Promise.all([
    security.agent.run({ prompt: "Audit src/ for SQL injection vulnerabilities" }),
    performance.agent.run({ prompt: "Profile the hot paths in src/api/ and optimize" }),
    docs.agent.run({ prompt: "Generate API documentation for all public exports" }),
  ])
  ```

  ```python box.py theme={"system"}
  import asyncio
  import os
  from upstash_box import AsyncBox

  async def main() -> None:
      seed = await AsyncBox.create(
          runtime="node",
          git={"token": os.environ["GITHUB_TOKEN"]},
      )
      await seed.git.clone(repo="github.com/your-org/monorepo")
      snap = await seed.snapshot(name="repo-cloned")
      await seed.delete()

      security, performance, docs = await asyncio.gather(
          AsyncBox.from_snapshot(snap.id),
          AsyncBox.from_snapshot(snap.id),
          AsyncBox.from_snapshot(snap.id),
      )

      await asyncio.gather(
          security.agent.run(prompt="Audit src/ for SQL injection vulnerabilities"),
          performance.agent.run(prompt="Profile the hot paths in src/api/ and optimize"),
          docs.agent.run(prompt="Generate API documentation for all public exports"),
      )

  asyncio.run(main())
  ```
</CodeGroup>
