How to use snapshots for faster sandbox startup

Learn how to save sandbox state with snapshots and skip installation on future runs.

4 min read
Last updated February 2, 2026

Every time you create a new sandbox, you start with a fresh environment. If your setup involves installing dependencies, cloning repositories, or building code, it can take a while. Snapshots let you save that configured state and create new sandboxes from it, skipping the setup entirely.

With snapshots, you:

  1. Set up your environment once (install dependencies, configure tools)
  2. Save the configured state as a snapshot
  3. Launch future sandboxes from that snapshot with everything already in place

Snapshots persist across sessions, so you can reuse them without repeating setup.

Before you begin, make sure you have:

  • Vercel CLI installed (npm install -g vercel)
  • Node.js 22 or later
  • A Vercel project to link your sandbox and generate an OIDC token

Create a new directory and install dependencies:

mkdir sandbox-snapshot-demo
cd sandbox-snapshot-demo
pnpm init
pnpm add @vercel/sandbox dotenv
pnpm add -D @types/node
vercel link
vercel env pull

This installs the SDK, links to your Vercel project, and creates .env.local with authentication credentials.

Create index.ts with the code below. It runs in two modes:

  • First run: Create sandbox, install dependencies, take snapshot
  • Second run: Create sandbox from snapshot (deps already there)
import { config } from 'dotenv';
config({ path: '.env.local' });
import { Sandbox, Snapshot } from '@vercel/sandbox';
import { writeFileSync, readFileSync, existsSync } from 'fs';
const ID_FILE = './snapshot-id.txt';
async function main() {
if (existsSync(ID_FILE)) {
const snapshotId = readFileSync(ID_FILE, 'utf-8').trim();
const snapshot = await Snapshot.get({ snapshotId });
const sandbox = await Sandbox.create({
source: { type: 'snapshot', snapshotId: snapshot.snapshotId },
timeout: 10 * 60 * 1000,
});
console.log(`Created from snapshot: ${sandbox.sandboxId}`);
// Verify deps are pre-installed
const result = await sandbox.runCommand({ cmd: 'ls', args: ['node_modules'] });
const count = (await result.stdout()).split('\n').filter(Boolean).length;
console.log(`Found ${count} packages in node_modules`);
await sandbox.stop();
} else {
await createAndSnapshot();
}
}
async function createAndSnapshot() {
const sandbox = await Sandbox.create({ timeout: 10 * 60 * 1000 });
console.log(`Created: ${sandbox.sandboxId}`);
const deps = ['typescript', 'eslint', 'prettier', 'zod'];
await sandbox.runCommand({
cmd: 'npm',
args: ['install', ...deps],
stdout: process.stdout,
stderr: process.stderr,
});
const snapshot = await sandbox.snapshot();
writeFileSync(ID_FILE, snapshot.snapshotId);
console.log(`Snapshot saved: ${snapshot.snapshotId}`);
console.log('Run again to restore from snapshot');
}
main().catch(console.error);

To measure the speedup you get from snapshots, use the below version. It records the cold-start time on the first run, then prints the warm-start time (and savings) on the second run.

import { config } from 'dotenv';
config({ path: '.env.local' });
import { Sandbox, Snapshot } from '@vercel/sandbox';
import { writeFileSync, readFileSync, existsSync } from 'fs';
const ID_FILE = './snapshot-id.txt';
const TIME_FILE = './cold-start.txt';
const read = (f: string) => readFileSync(f, 'utf-8').trim();
const write = (f: string, v: string) => writeFileSync(f, v);
async function main() {
if (existsSync(ID_FILE)) {
const snapshotId = read(ID_FILE);
const coldMs = existsSync(TIME_FILE) ? +read(TIME_FILE) : null;
const snapshot = await Snapshot.get({ snapshotId });
const start = Date.now();
const sandbox = await Sandbox.create({
source: { type: 'snapshot', snapshotId: snapshot.snapshotId },
timeout: 10 * 60 * 1000,
});
const warmMs = Date.now() - start;
console.log(`Warm start: ${(warmMs / 1000).toFixed(2)}s`);
if (coldMs) {
console.log(`Cold start: ${(coldMs / 1000).toFixed(2)}s → ` +
`saved ${((coldMs - warmMs) / 1000).toFixed(1)}s`);
}
await sandbox.stop();
} else {
const start = Date.now();
const sandbox = await Sandbox.create({ timeout: 10 * 60 * 1000 });
const deps = ['typescript', 'eslint', 'prettier', 'zod'];
await sandbox.runCommand({
cmd: 'npm',
args: ['install', ...deps],
stdout: process.stdout,
stderr: process.stderr,
});
const snapshot = await sandbox.snapshot();
write(ID_FILE, snapshot.snapshotId);
write(TIME_FILE, String(Date.now() - start));
console.log(`Snapshot saved, run again to restore`);
}
}
main().catch(console.error);

Execute the script twice:

pnpm dlx tsx index.ts

First execution:

Created: sbx_abc123
added 88 packages in 6s
Snapshot saved: snap_xyz789
Run again to restore from snapshot

Second execution:

Created from snapshot: sbx_def456
Found 77 packages in node_modules

With timing comparison enabled:

Warm start: 0.41s
Cold start: 16.49s → saved 16.1s

Call snapshot() on a running sandbox to save its state:

const snapshot = await sandbox.snapshot();
console.log(snapshot.snapshotId); // snap_abc123

Important: The sandbox stops automatically after snapshotting. You cannot run more commands on it.

Pass the snapshot ID as the source when creating a new sandbox:

const sandbox = await Sandbox.create({
source: { type: 'snapshot', snapshotId: snapshot.snapshotId },
timeout: 10 * 60 * 1000,
});
  • You can create multiple sandboxes from the same snapshot
  • Deleting a snapshot does not affect sandboxes already created from it

For more details, see the Snapshotting documentation.

ScenarioUse
Keep sandbox warm between commandsSandbox.get()
Reuse setup across sessions/daysSnapshot
Share environment with teammatesSnapshot
Survive sandbox timeoutSnapshot
Fastest possible reconnectSandbox.get()

Was this helpful?

supported.