# Named checkpoints
URL: /docs/core/concepts/named-checkpoints

Tag checkpoints with human-readable names, list them, and resume from any specific point.



By default, `client.resume()` restores from the most recent checkpoint. Named checkpoints let you tag specific points in a session and resume from any of them by name.

## Tagging a checkpoint [#tagging-a-checkpoint]

Pass a string to `sb.checkpoint()` to attach a tag:

```ts
await sb.exec("apt-get install -y python3-pip");
await sb.checkpoint("after-apt");

await sb.exec("pip install numpy pandas scikit-learn");
await sb.checkpoint("after-pip");

await sb.exec("python3 -c 'import sklearn; print(sklearn.__version__)'").pipe(process.stdout);
```

The tag is stored in the ledger alongside the snapshot ID. It has no effect on the snapshot itself.

## Listing checkpoints [#listing-checkpoints]

`sb.listCheckpoints()` returns all checkpoints for the sandbox in creation order:

```ts
const checkpoints = await sb.listCheckpoints();

for (const cp of checkpoints) {
  console.log(cp.tag, cp.snapshotId, new Date(cp.createdAt).toISOString());
}
// after-apt   snap_abc123  2024-01-15T10:00:00.000Z
// after-pip   snap_def456  2024-01-15T10:02:30.000Z
```

Each `CheckpointInfo` has:

| Field        | Type      | Description                                         |
| ------------ | --------- | --------------------------------------------------- |
| `snapshotId` | `string`  | OpenSandbox snapshot ID                             |
| `tag`        | `string?` | Tag passed to `sb.checkpoint()`, if any             |
| `createdAt`  | `number`  | Unix timestamp (ms) when the checkpoint was created |

## Resuming from a named checkpoint [#resuming-from-a-named-checkpoint]

Pass `{ tag }` to `client.resume()` to restore from a specific checkpoint instead of the latest:

```ts
const sandboxId = sb.sandboxId;

// resume from the earlier checkpoint, skipping the pip install state
const sbResume = await client.resume(sandboxId, { tag: "after-apt" });

try {
  // execs before "after-apt" are replayed from cache
  await sbResume.exec("apt-get install -y python3-pip");

  // runs live on the "after-apt" snapshot — pip packages are gone here
  await sbResume.exec("pip install torch").pipe(process.stdout);
} finally {
  await sbResume.close();
}
```

Without a tag, `client.resume()` falls back to the most recent checkpoint — existing behaviour is unchanged.

`client.resume()` throws `SandboxClientError` (status 404) if no checkpoint with the given tag is found in the session's ledger.

## Example: branching from a base state [#example-branching-from-a-base-state]

A common pattern is to take one base checkpoint and branch different experiments from it:

```ts
const sb = await client.sandbox({
  image: "python:3.11-slim",
  resources: { cpu: "1", memory: "1Gi" },
  name: "ml-experiment",
});

try {
  await sb.exec("pip install -q numpy");
  await sb.checkpoint("base");
  await sb.close();
} catch (err) {
  await sb.close();
  throw err;
}

const sandboxId = sb.sandboxId;

// Branch A: add pandas
const branchA = await client.resume(sandboxId, { tag: "base" });
try {
  await branchA.exec("pip install -q pandas");
  await branchA.exec("python3 -c 'import pandas; print(pandas.__version__)'").pipe(process.stdout);
} finally {
  await branchA.close();
}

// Branch B: add torch — restores from the same base snapshot
const branchB = await client.resume(sandboxId, { tag: "base" });
try {
  await branchB.exec("pip install -q torch --index-url https://download.pytorch.org/whl/cpu");
  await branchB.exec("python3 -c 'import torch; print(torch.__version__)'").pipe(process.stdout);
} finally {
  await branchB.close();
}
```

Both branches restore from the same `"base"` snapshot independently — no interference between them.
