# Informational route JavaScript budgets Run after the existing production build; no second build or server is needed: ```sh node scripts/performance-report.mjs --next-dir .next --config scripts/performance-budgets.json --output-dir build-reports ``` The command writes `report.json` and `report.md` and prints the Markdown report. An optional `PERFORMANCE_COMMIT_SHA` environment variable records the commit declared by the build caller; the script does not infer that an existing build matches the current checkout. JSON also records `BUILD_ID`, Node/zlib versions, manifest provenance, exact file paths, sizes and source entries. ## What is measured For each configured App Router route, resolve its exact app path using `app-path-routes-manifest.json` and `server/app-paths-manifest.json`. Read its generated `page_client-reference-manifest.js` as a JSON assignment **without executing JavaScript**. Use its sibling `page/build-manifest.json`, falling back to the root build manifest only if that sibling is absent. The **initial entry envelope** is the union of route bootstrap `rootMainFilesTree[appPath]` (or `rootMainFiles`) and every `entryJSFiles` list in that route's client-reference manifest. This includes layout, page and boundary/loading entries. The definition follows the data exposed by the installed Next 16.3.4 Turbopack build and the `getLinkAndScriptTags` / `getRequiredScripts` renderer helpers; it is deliberately a build-artifact envelope, not a browser network trace. Conditional rendering, redirects, streaming and browser caches can change actual requests. - Raw bytes are filesystem byte lengths of unique JavaScript assets in that envelope. - Gzip bytes are the **sum of independent gzip level 9 compressions** of those files using the recorded Node/zlib runtime. They are not gzip of concatenated source, nor observed CDN transfer sizes. - Deployment query strings and `/_next/` prefixes are normalized before deduplication. Shared files count once per route; each route is measured independently, with no misleading cross-route total. - Legacy `nomodule` polyfills are measured separately, outside the modern initial budget. CSS, source maps, images, external scripts, HTML/RSC payloads and async-only chunks absent from `entryJSFiles` are excluded. - This report makes no claims about execution cost, LCP, hydration time or real-user performance. ## Initial limits The first limits are **baseline bytes × 1.15, rounded upward to the next 10 KiB (10,240 bytes)** independently for raw and gzip. They are provisional size alerts, not validated speed targets. Baseline: existing local production build `build-TfctsWXpff2fKS`, Next 16.3.4; its source commit was not inferred. | Route | Baseline raw bytes | Baseline gzip bytes | Raw limit | Gzip limit | | --- | ---: | ---: | ---: | ---: | | `/me` | 767156 | 238571 | 890880 | 276480 | | `/news` | 765367 | 237599 | 880640 | 276480 | | `/events` | 765851 | 237964 | 890880 | 276480 | | `/search` | 765851 | 237964 | 890880 | 276480 | | `/admin/catalog` | 1654898 | 492619 | 1904640 | 573440 | | `/admin/studio/furni` | 1241312 | 391541 | 1433600 | 450560 | Configured limits are positive integer bytes; `null` explicitly means observe-only. `scripts/performance-budgets.json` remains `mode: informational`. Exceeding a limit produces `over-budget` and a warning, with exit code 0. Missing production `BUILD_ID`, unsupported manifests, missing routes or missing referenced assets produce `unavailable` with a reason and **no partial/zero total**, also exit code 0. Malformed budget configuration or an unwritable output directory fails the command. This keeps initial CI reporting non-blocking while preventing invalid configuration from quietly disabling limits. Synthetic tests cover shared-chunk deduplication, exact byte/gzip calculations, route bootstrap selection, missing data, safe parsing and CLI exit behavior. Run `pnpm exec vitest run --coverage.enabled=false scripts/performance-report.test.mjs`.