Requirements
- Next.js 15 or 16, App Router
- Node 20+
- A production build. crust refuses to measure
next dev— dev output is unminified, unbundled and HMR-laden, so any number taken from it is fiction.
@moumen/crust as a development dependency, or use npx directly. The package is scoped;
the executable and the product are both named crust.
1. Build, then analyze
.perf/ using one file per build. Two branches can record builds without
editing a shared history file.
Reading the columns
- First load is the JavaScript downloaded on the first visit, including shared root chunks.
- Shell is the share of visible rendered output outside pending Suspense boundaries.
- Mode is
static,partial,isr,dynamic, orhandler. - Indented
↳lines name the reason for a mode or hole. ✂names a component that was postponed out of the shell.
2. See it visually
3. Compare against a baseline
After a change, rebuild and diff:Unlock per-file attribution
Route sizes, rendering modes, dynamic-route blame and shell composition all work out of the box. Tracing bytes to a specific file needs source maps in the production build:next.config.ts
packages/features/src/course/… is 340 kB of it”.
Next steps
Understand regressions
Automatic checks, explicit ceilings, comparability, and intentional exceptions.
Add the CI check
Regression enforcement, budgets, a PR comment, and history on an orphan branch.