Next 15 & 16webpackTurbopack

Know what shipped instantly,
and what fell out

crust maps your App Router project from source, joins it to the build output, and keeps a snapshot per build — so a regression traces back to the commit and the import that caused it.

1$ next build && npx crust diff main
2
3crust diff cfdcf500 → 4a802397
4
5/products/[slug] 543.2 kB +0.0 kB
6    shell 100% → 45%
7    ✂ <ProductGallery> left the shell
8      uncached fetch at lib/http.ts:3
9
102 budget breaches · exit 1

How it works

Read the build, predict the shell, check the prediction, then compare against last time.

crust report
RouteFirst loadShellMode/543.2 kBstatic/products/[slug]543.2 kBpartial/dashboard527.4 kBpartial
Pull request

crust: 2 budget breaches ✗

/dashboard — static shell is 39%, below the 60% floor
blame: cookies() at app/dashboard/page.tsx:18
/products/[slug] — static shell is 45%, below the 60% floor
blame: uncached fetch at lib/http.ts:3
<ProductGallery> left the static shell

No build error was produced and no bundle grew. A use cache directive was removed three call frames below the page, and 55% of the route silently stopped being static.

What you get

A CLI, a snapshot store you can commit, a GitHub Action, an HTML report and an in-page widget.

Route-level attribution

Every byte of first-load JS traced to the file that produced it — through barrel files, monorepo packages and both bundlers.

Static shell composition

What is prerendered, what is postponed, and the exact call site that pushed each component out of the shell.

Regression blame

A snapshot per build, keyed on more than the git SHA. Diffs name the module responsible, not just the route that grew.

A check that fails

Budgets on bundle size and shell ratio. The PR comment updates in place instead of stacking on every push.

Runtime, in the page

Web Vitals, long animation frames, an image audit and the streaming waterfall — behind a build-time gate.

Honest unknowns

Anything not lexically resolvable is reported as unknown. A predictor that guesses wrong poisons every number beside it.

What it is not

Permanent, and written down before the first user arrived.

Not a runtime APM. No error tracking, no distributed tracing, no alerting.
Not a Lighthouse replacement. It measures what your build produced, not a lab score.
Not multi-framework. Next.js App Router only. Pages Router is detect-and-warn.
Not a hosted service. No accounts, no dashboard. Your snapshots live in your repo.
Not a bundler. It reads build output and never changes how your app builds.

Find out what your shell actually contains

crust reads a production build. It refuses to measure dev output, because dev numbers are fiction.