Getting Started
Introduction
Boot performance is easy to break and hard to see. A single stray static import of a heavy SDK silently lands its whole module on the boot bundle:
import * as Sentry from '@sentry/nextjs'on a boot-reachable file adds real weight to Total Blocking Time (TBT), even if you only callinit()later — deferring the call doesn't defer the parse.- A root-barrel import (e.g.
@/components) can drag a validation library or an accessibility library onto a route that never needed it. - Replacing a
dynamic import()with a static one removes a code-split boundary — the whole graph behind it lands on boot instead.
None of these throw an error. You find out from users, or a Lighthouse score that crept down over
several unrelated PRs. And when you do measure, it's easy to draw the wrong conclusion: machine
load can swing Total Blocking Time by 2× between two runs of the exact same build, and grepping a
bundle for a package's import-path string false-positives on the very import('...') call sites
that are already lazy.
@codeleap/perf exists to make this fast, repeatable, and honest — a CLI for React web projects (Next.js first, but the static analyzers work on any bundled output with a manifest) that:
| You want to… | Command | Needs a server? |
|---|---|---|
| Know if a heavy library is on boot (seconds) | boot-graph | no |
| See which third-party packages the boot graph pulls | imports | no |
| See chunk sizes and duplication of a configured library across chunks | chunks | no |
| Get real TBT/LCP/FCP, by floor rather than noisy median | measure | yes |
| Explore boot CPU self-time by library (a secondary, exploratory signal) | cpu | yes |
| Run everything and get a PASS/FAIL verdict, e.g. for CI | analyze | optional |
It also bakes in the methodology that keeps the numbers trustworthy — SDK-internal markers instead of package-name substrings, comparison by floor instead of mean/median, and machine load recorded alongside every report — covered in Measuring Correctly.
Installing the Library
bun add -d @codeleap/perf
Then add a script:
{ "scripts": { "perf": "codeleap-perf analyze" } }
The codeleap-perf binary resolves from the installed package — no relative paths to a monorepo
are required, so this works the same in a single-repo project as it does in a workspace.
Quick Start
# 1. Build the app — the static analyzers read the build output (Next.js: .next/)
bun run build
# 2a. Static-only — fast, no server, good for a pre-commit or CI-lint step
codeleap-perf analyze --no-server
# 2b. Full — start a prod server first, then measure too
bun run start &
codeleap-perf analyze
analyze always runs the static checks; it adds measure (and cpu, with --cpu) when a
server is reachable, and exits with code 1 on a failing verdict so CI can gate a merge on it.
That one command is enough for day-to-day use — the full breakdown of every command's output,
every config field, and the programmatic API lives in the Reference.
Next steps
- Command & Config Reference — every command's exact output, the full config field table, and the programmatic API's return types.
- Measuring Correctly — the metrics, the methodology, and how not to fool yourself with a noisy machine.
- Improving Boot Performance — a general playbook of changes that move TBT, and the comment-and-measure discipline used to validate each one.