sandbox-bench

Benchmark React or Next.js changes on Vercel Sandbox VMs with paired A/B statistics: react PR/commit vs base, or Next.js PR/commit vs base, measured end-to-end through the bench/render-pipeline app (rps, latency, p95; TTFB, RSS and document/Flight bytes when the Next side captures them) and, for React changes, through the react repo's flight-ssr-bench fixture (Node AND Edge web-streams paths, Fizz and Flight+Fizz). Use whenever the user asks to bench, perf test, or A/B a React PR, a react-server-dom / Flight / vendored React change, or a Next.js PR ("is this PR faster", "does this regress RSC?", "measure the perf impact of <commit>"), even if they don't say "benchmark" — any request to quantify a server-side performance difference between two revisions belongs here. Runs remotely (laptop-free), applies correctness gates before measuring, and reports boot-level confidence intervals.

Install
npx skills add 'https://github.com/vercel/next.js/tree/canary/.agents/skills/sandbox-bench'
Download bundle ↓
canary · bfcf687Scanned 2026-09-15

Contributors

GitHub-linked commit authors for this SKILL.md at the saved revision. Co-authors and history before file renames are not included.

File history ↗
View on GitHub
← Back to SKILL.md
// List/remove leaked bench sandboxes. Every VM the skill's scripts// create is named sbench-* and tagged purpose=sandbox-bench; the// harnesses remove their VMs in finally blocks, but a killed local// process leaks them until their timeout.//// The project may be shared, so removal is deliberately conservative:// a VM is only listed when its name matches, its tag matches, AND it is// older than --min-age-hours (default 3 — longer than any healthy run),// and removal is per exact listed name.////   node sandbox-sweep.mjs                     # list what would be removed//   node sandbox-sweep.mjs --yes               # remove//   node sandbox-sweep.mjs --min-age-hours 0   # include fresh VMs (danger://                                              # only when nothing is active)import { execFile } from 'child_process'import { promisify } from 'util'import { loadConfig, sandboxScope } from './config.mjs' const execFileP = promisify(execFile)const CONFIG = loadConfig()const SCOPE = sandboxScope(CONFIG)const argv = process.argv.slice(2)const minAgeHours = argv.includes('--min-age-hours')  ? Number(argv[argv.indexOf('--min-age-hours') + 1])  : 3 // Age from the CLI's "CREATED" column ("32 minutes ago", "2 hours ago").function ageHours(words) {  const i = words.findIndex((w) => w === 'ago')  if (i < 2) return Infinity  const n = Number(words[i - 2])  const unit = words[i - 1]  if (!Number.isFinite(n)) return Infinity  if (unit.startsWith('second')) return n / 3600  if (unit.startsWith('minute')) return n / 60  if (unit.startsWith('hour')) return n  return n * 24} // Paginate: the CLI prints a cursor hint line when more pages exist.const found = []let cursorfor (let page = 0; page < 50; page++) {  const args = ['sandbox', 'list', '--limit', '100', ...SCOPE]  if (cursor) args.push('--cursor', cursor)  const { stdout, stderr } = await execFileP(CONFIG.vercelBin, args, {    maxBuffer: 1 << 24,  })  for (const line of stdout.split('\n')) {    const words = line.trim().split(/\s+/)    const name = words[0]    if (!/^sbench-/.test(name)) continue    if (!line.includes('purpose:sandbox-bench')) continue    const age = ageHours(words)    if (age < minAgeHours) {      console.log(        `skipping ${name} (${age.toFixed(1)}h old < --min-age-hours ${minAgeHours})`      )      continue    }    found.push(name)  }  cursor = `${stdout}\n${stderr}`.match(/--cursor\s+(\S+)/)?.[1]  if (!cursor) break} if (!found.length) {  console.log('no leaked bench sandboxes found')  process.exit(0)}const doIt = argv.includes('--yes')let failures = 0for (const name of found) {  if (doIt) {    try {      await execFileP(CONFIG.vercelBin, ['sandbox', 'rm', name, ...SCOPE])      console.log(`removed ${name}`)    } catch (e) {      failures++      console.error(`could not remove ${name}: ${e.message.split('\n')[0]}`)    }  } else {    console.log(`would remove ${name} (pass --yes)`)  }}process.exit(failures ? 1 : 0) 
Referenced from SKILL.md