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.
@moumensoliman/crust as a development dependency, or use npx directly. The package name differs
from the executable; the product and executable are both named crust.
1. Set it up in one command
init finds the app, records the first snapshot, writes starter budgets you can argue with, and
generates a CI workflow pinned to this crust version. It reports what it decided at every step, and
replaces nothing without --force - --dry-run shows the plan first. See the
CLI reference for the seven steps and the generated files.
In a monorepo, point it at the app: npx @moumensoliman/crust init --cwd apps/web. With several apps
and no pointer, it lists them and stops instead of measuring the wrong one.
The rest of this page is what init does one command at a time, and what the output means.
2. Build, then analyze
--routes for the full route inventory, --verbose for coverage counts and analysis gaps, or
--report for the HTML report.
The snapshot is written to .perf/ using one file per build. Two branches can record builds without
editing a shared history file. See snapshot files for what to commit and
what remains generated.
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.
3. See it visually
4. Compare production builds
First record the base branch, then rebuild and diff after your change:Compare two branches in one command
The pair above needs a snapshot on each side, which the first comparison of two branches never has.--build records them for you:
.perf/, and the
output is the diff above. Your checkout does not move - run it from a dirty working tree on a third
branch. See the CLI reference for --parallel, monorepo --cwd, and how
a differing lockfile is handled.
The two builds must use the same bundler, Next.js major, and snapshot schema. If they do not, crust
names the incompatibility and refuses to assign a cause.
The decision is shared with crust ci: BLOCK, REVIEW, CLEAR, or CANNOT DECIDE. Improvements
appear alongside regressions, and attribution beside the verdict tells you how much of the cause
explanation the build supports.
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.
Ask an agent
Point your coding agent at the same evidence over MCP, or run one tool with
crust ask.