Without a performance budget enforced in CI, bundle size, LCP, and CLS regressions go undetected until users report slowness (ISO-25010 capacity). A JavaScript bundle that grew from 150 KB to 500 KB over six months — one dependency upgrade at a time — produces no build error and no alert. Performance budgets create an automated gate: the build fails when the bundle exceeds the limit, turning performance regression into a first-class CI failure alongside type errors and test failures. Without this gate, performance optimization is reactive rather than preventive.
Info because missing performance budgets allow regressions to ship silently over time, but the immediate impact is potential rather than confirmed — a process gap rather than a current defect.
Define and enforce performance budgets in your build pipeline using size-limit:
// package.json
{
"scripts": {
"size": "size-limit"
},
"size-limit": [
{ "name": "main bundle", "path": ".next/static/chunks/main-*.js", "limit": "200 KB" },
{ "name": "styles", "path": ".next/static/css/**.css", "limit": "50 KB" }
]
}
Add to CI (.github/workflows/ci.yml):
- name: Check bundle sizes
run: npm run size
For Core Web Vitals budgets, add Lighthouse CI:
- name: Lighthouse CI
run: lhci autorun
env:
LHCI_GITHUB_APP_TOKEN: ${{ secrets.LHCI_GITHUB_APP_TOKEN }}
Set initial budget limits from your current measured baselines — then tighten by 10% each quarter. The goal is regression prevention, not aspirational targets that immediately fail every build.
ID: performance-core.script-style-efficiency.performance-budget
Severity: info
What to look for: Count all relevant instances and enumerate each. Check for performance budget configuration in build tooling (webpack, Vite, Next.js). Look for size limits on bundles, CSS, images in package.json, next.config.ts, or separate config files. Check whether CI/CD fails if budgets are exceeded.
Pass criteria: Performance budgets are defined for key metrics: JS bundle size (gzipped), CSS bundle size, image count/size, LCP target, FID/INP target, CLS target. Build process validates against budgets and fails if exceeded.
Fail criteria: No performance budget defined, or budgets exist but are not enforced. Build does not fail if metrics exceed budgets.
Skip (N/A) when: The project is very small (single page, minimal JS) and budget enforcement is overkill.
Detail on fail: Describe the missing budget. Example: "No performance budget configured. JS bundle grew to 500KB gzipped unnoticed; no CI check would catch regressions" or "Budget mentioned in docs but not enforced in build; developers unaware when they exceed it".
Remediation: Define and enforce performance budgets:
With webpack-bundle-analyzer:
// webpack.config.js
const webpackBundleAnalyzer = require('webpack-bundle-analyzer')
module.exports = {
plugins: [
new webpackBundleAnalyzer.BundleAnalyzerPlugin({
analyzerMode: 'static',
maxSize: 250000 // 250KB gzipped budget
})
]
}
With Vite:
// vite.config.ts
import { defineConfig } from 'vite'
export default defineConfig({
build: {
rollupOptions: {
output: {
// Configure code splitting and monitor sizes
}
}
}
})
With Next.js:
{
"scripts": {
"size": "next build && size-limit"
},
"size-limit": [
{ "name": "app.js", "path": ".next/static/chunks/main.js", "limit": "200KB" },
{ "name": "styles.css", "path": ".next/static/css/**.css", "limit": "50KB" }
]
}