awesome-everything RU
↑ Back to the climb

Performance

CI enforcement and RUM: making budgets stick

Crux Without a CI gate, a bundle budget is an aspiration. With size-limit in CI and RUM in production, every PR that blows the budget fails, and every production regression pages the owning team.
Your altitude — climbing toward senior
ZeroJuniorMiddleSenior
You are at middle altitude — in the sky
◷ 15 min

A team spends a week cutting the homepage bundle from 900 KB to 180 KB. Three months later it is back at 820 KB. No one violated any policy. Each engineer made a reasonable-looking import. Without a CI gate that fails PRs, the budget is aspirational — it erodes one PR at a time.

The CI gate: size-limit

size-limit is an open-source tool that reads per-route bundle targets from package.json or a config file and fails the build if any limit is exceeded. It runs after the build, reads gzip’d chunk sizes, and exits non-zero if anything is over budget.

// package.json
"size-limit": [
  { "name": "Homepage JS", "path": ".next/static/**/_app-*.js", "limit": "100 KB" },
  { "name": "Dashboard JS", "path": ".next/static/**/dashboard-*.js", "limit": "250 KB" },
  { "name": "All pages total", "path": ".next/static/**/*.js", "limit": "500 KB" }
]
# .github/workflows/perf.yml
- name: Build
  run: bun run build
- name: Check bundle size
  run: npx size-limit
  # Fails PR if any limit exceeded

The PR comment integration (size-limit-action) posts a table of current vs budgeted size on every PR, making the impact visible before merge. Engineers who add a library see the delta immediately; they either justify the addition (and the team explicitly raises the budget) or find a smaller alternative.

Alternative: bundlewatch, Lighthouse CI

bundlewatch is similar to size-limit with a different config format and GitHub check integration. Lighthouse CI runs a full Lighthouse audit on every PR — more comprehensive, slower. All three tools answer the same question: “does this PR blow the performance budget?”

Senior teams use size-limit for fast per-PR feedback (runs in 5-10 s) and Lighthouse CI on main branch merges for a full CWV snapshot.

The bundle analyzer workflow

Before CI can enforce a budget, the team must understand the current bundle. The standard workflow:

  1. Enable the bundle analyzer: ANALYZE=true bun run build (Next.js: @next/bundle-analyzer; Vite: rollup-plugin-visualizer; Webpack: webpack-bundle-analyzer).
  2. Sort by size. Identify the top 5-10 contributors.
  3. For each: ask “is this needed on the critical path of this route?”
  4. Common findings: moment.js (220 KB, replace with date-fns); lodash full (80 KB, cherry-pick); admin panel imported globally (170 KB, lazy-load); all icon variations (110 KB, cherry-pick).
  5. Set the initial budget at current size + 20% (room to grow, but not unlimited).
ToolPurposeWhen to use
size-limitFails PR if bundle > budgetEvery PR
Bundle analyzerVisual treemap of modulesBefore and after optimisations
Lighthouse CIFull synthetic CWV auditOn merge to main
RUMReal-user LCP/INP/CLS metricsContinuous production monitoring

RUM in production

CI catches regressions before merge. RUM catches what CI misses in production: device classes that perform worse than the throttled test, geographies with slow networks, and slow regressions that accumulate over many small PRs each within budget.

Implementations: Web Vitals JS library (Google, free), Sentry Performance, Datadog RUM, New Relic Browser, Vercel Speed Insights, Cloudflare Web Analytics.

Senior RUM dashboard: P75 LCP per route, per device class (mobile vs desktop), per geography. Alert when P75 LCP for any route degrades more than 20% for 24 hours.

Connecting RUM to bundle size: some teams ship the gzip’d bundle size as a custom RUM metric alongside LCP, so when LCP degrades the first dashboard to check shows the bundle size delta for the same deploy. Makes the correlation visible without inference.

The budget raise protocol

When a PR legitimately needs to exceed a budget: the engineer opens a budget-raise PR. It requires sign-off from the performance-owning team lead, documents the justification (new feature, vendor requirement, user value), and records the old and new limits in perf-budgets.json. Without this protocol, budgets drift upward one implicit approval at a time.

Why this works

Why does the initial budget include a +20% buffer? Setting the budget at the current measured size means the next feature addition immediately fails CI, which is demoralising and counterproductive. A 20% buffer acknowledges that features grow bundles and forces explicit justification only when growth exceeds the buffer. Tighten the budget 10% per quarter as a ratchet — continuous improvement without a cliff.

Quiz

A PR adds a 60 KB chart library to the homepage. The CI gate fails. The engineer says the chart is important. What is the correct process?

Quiz

Lighthouse CI runs on every PR and reports P75 LCP as 2.1 s. Production RUM shows P75 LCP as 4.8 s on mobile. Why the discrepancy?

Quiz

A team sets a size-limit budget of 100 KB for homepage JS. A month later the budget is raised to 150 KB, then 180 KB, then 200 KB — each time for a 'critical' feature. What structural problem is this and how do you fix it?

Recall before you leave
  1. 01
    Describe the complete bundle-budget enforcement stack: PR time, merge, and production.
  2. 02
    Why does Lighthouse CI sometimes show Good LCP while production RUM shows Poor LCP for the same route?
Recap

A bundle budget without a CI gate is a suggestion. size-limit, bundlewatch, or Lighthouse CI makes every over-budget PR fail automatically. The bundle analyzer provides the visibility to understand what is inside each chunk and where to cut. RUM completes the loop in production, catching slow regressions and device-class issues that synthetic tests miss. The budget-raise protocol ensures every limit change is explicit and reviewed. The next and final lesson covers the senior layer: V8’s JIT pipeline and how HTTP/3 resource priorities interact with bundle delivery.

Connected lessons
appears again in260
Continue the climb ↑V8 JIT pipeline, HTTP priorities, and bundle security
shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.