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
#!/usr/bin/env node// Post-hoc (re-)analysis of runs at the boot level. Reads ONLY the// results db: a run-dir argument is imported (idempotently) and// verified first, a bare run id analyzes what the db already holds.//   node bench-analyze.mjs <runDir|runId> [--base <arm>] [--cand <arm>]import fs from 'node:fs'import path from 'node:path'import { analyzeE2eRows } from './bench-stats.mjs'import { openDb, importRun, loadRows, runMeta, verify } from './bench-db.mjs' const argv = process.argv.slice(2)const target = argv.find((a) => !a.startsWith('--'))const get = (name) => {  const i = argv.indexOf(name)  return i >= 0 ? argv[i + 1] : undefined}if (!target) {  console.error(    'usage: node bench-analyze.mjs <runDir|runId> [--base arm] [--cand arm]'  )  process.exit(1)}const db = openDb()let runIdif (fs.existsSync(target)) {  runId = importRun(db, target).runId} else {  runId = path.basename(target)}const { failures, notes } = verify(db, runId)for (const n of notes) console.log(`note: ${n}`)if (failures.length) {  console.error(`RESULTS DB VERIFY FAILED:\n  ${failures.join('\n  ')}`)  process.exit(1)}const rows = loadRows(db, runId)const arms = [...new Set(rows.map((r) => r.arm))]if (arms.length !== 2) {  console.error(`expected exactly 2 arms, found: ${arms.join(', ')}`)  process.exit(1)}// Which arm is base? Row order cannot answer this (ABBA runs the// candidate first), so require an explicit source: the run's meta,// a conventional name, or the --base flag.const meta = runMeta(db, runId)?.metaconst base =  get('--base') ??  (meta && arms.includes(meta.base) ? meta.base : undefined) ??  ['base', 'synced'].find((n) => arms.includes(n))if (!base) {  console.error(    `cannot determine the base arm from {${arms.join(', ')}}: ` +      'no meta, no arm named "base"/"synced" — pass --base <arm>'  )  process.exit(1)}const cand = get('--cand') ?? arms.find((a) => a !== base)const boots = new Set(rows.map((r) => r.vm)).sizeconsole.log(`${runId}  boots=${boots}  arms: ${base} (base) vs ${cand}`)if (meta?.pr)  console.log(    `PR: ${meta.pr.title ? `"${meta.pr.title}" — ` : ''}${meta.pr.url}`  )for (const a of meta?.arms ?? [])  if (a.title) console.log(`  ${a.name}: "${a.title}"`)if (rows[0].route === '') {  // Micro (sandbox-ab) samples: phase holds the payload name.  analyzeE2eRows(rows, base, cand, ['mean', 'p50', 'p95', 'p99', 'gcMs'])} else if (meta?.suite === 'ssr') {  analyzeE2eRows(rows, base, cand, [    'rps',    'mean',    'median',    'p95',    'p99',    'gcMs',    'heapMb',  ])} else {  // No p99 for e2e: the load phases are far too small for it.  analyzeE2eRows(rows, base, cand, [    'rps',    'median',    'mean',    'p95',    'ttfb',    'docKb',    'gzipKb',    'flightKb',    'rss',    'rssHw',  ])} 
Referenced from SKILL.md