Home›Performance Tools›Performance Budgets

Performance Budgets: Setting and Enforcing Limits

Web performance degrades gradually. No single pull request makes a page slow — it is the accumulation of an extra analytics script here, an unoptimized image there, a new feature component that adds 40 KB of JavaScript. Without explicit constraints, performance erodes through hundreds of individually reasonable decisions that compound into a perceptibly slower experience. Performance budgets are those constraints: measurable limits on metrics that matter, enforced at the point where performance-degrading changes enter the codebase.

This guide covers the three types of performance budgets, how to derive meaningful limits from data rather than aspiration, how to enforce them in CI/CD pipelines, how to get team buy-in, and how to evolve budgets as the application and user base change.

Three Types of Performance Budgets

Performance budgets fall into three categories, each measuring a different dimension of page weight and speed. Effective budget strategies combine all three because no single category captures the complete picture.

Size-Based Budgets

Size budgets limit the total transfer size of page resources. They are the simplest to measure and enforce because file sizes are deterministic — the same build always produces the same byte counts, independent of network conditions or device capability.

Resource TypeStarter BudgetAggressive BudgetRationale
Total page weight500 KB300 KBTransfer budget for entire page including all resources
JavaScript (compressed)170 KB100 KBLargest contributor to TBT; parse + compile + execute cost
CSS (compressed)50 KB30 KBRender-blocking; excess CSS delays FCP
Images (total)200 KB150 KBOften largest by byte count; format and sizing optimization
Fonts (total)80 KB50 KBRender-blocking for text; subsetting reduces waste
Third-party scripts100 KB50 KBOutside engineering control; budget limits proliferation

Timing-Based Budgets

Timing budgets limit how long key performance milestones take to reach. They directly reflect user experience but introduce variability because network conditions and server response times fluctuate between measurements. Use percentile-based assertions (p75 or p90) rather than single-run thresholds to account for this variability.

Quantity-Based Budgets

Quantity budgets limit the number of specific resource types. Each additional request carries overhead — DNS resolution, connection establishment, TLS negotiation — that size budgets do not capture. Quantity budgets also serve as architectural constraints, preventing the accumulation of third-party scripts and unused resources.

Deriving Budgets from Data

Aspirational budgets fail. A team that sets a 200 KB JavaScript budget when the current state is 800 KB will never reach it — the gap is too large, the budget is ignored within weeks, and the concept loses credibility. Effective budgets start from current reality and define achievable improvement targets.

The Baseline Method

Measure current performance across all budget dimensions. Use Lighthouse for lab metrics, RUM for field metrics, and build tooling for size metrics. Record the current state, then set initial budgets at 80 percent of the current values — tight enough to prevent regression but loose enough to avoid false positives from normal variance.

# Measure current JavaScript bundle sizes npx bundlesize --config bundlesize.config.json # bundlesize.config.json { "files": [ { "path": "dist/main.*.js", "maxSize": "170 KB", // Current: 160 KB + 10 KB buffer "compression": "gzip" }, { "path": "dist/vendor.*.js", "maxSize": "120 KB", // Current: 108 KB + 12 KB buffer "compression": "gzip" }, { "path": "dist/styles.*.css", "maxSize": "35 KB", "compression": "gzip" } ] }

The Competitive Method

Research competitor performance using WebPageTest comparisons. If your three closest competitors load in 2.5, 3.0, and 3.5 seconds, setting a budget of 2.0 seconds positions your site as the fastest in the category. This method anchors budgets in business context rather than arbitrary technical targets.

Budget Derivation Process 1. Measure Current baseline Lab + Field + Build 2. Benchmark Competitors Industry medians 3. Target 20% below current Beat top competitor 4. Enforce CI gates PR checks Quarterly review: tighten budgets as you improve

Enforcing Budgets in CI/CD

A budget that is not enforced is a suggestion. Enforcement means that a pull request that exceeds a budget cannot merge until the author either reduces the impact or successfully requests a budget increase. The enforcement mechanism must provide clear, actionable feedback: which budget was exceeded, by how much, and what changed to cause the breach.

Build-Time Size Checks

Size budgets integrate directly into the build pipeline. Tools like bundlesize, size-limit, and webpack's performance configuration check compressed file sizes against defined limits and fail the build if exceeded.

// webpack.config.js — built-in performance hints module.exports = { performance: { maxAssetSize: 250 * 1024, // 250 KB per asset maxEntrypointSize: 400 * 1024, // 400 KB total entrypoint hints: 'error' // 'warning' or 'error' } }; // size-limit configuration in package.json { "size-limit": [ { "path": "dist/index.js", "limit": "45 KB", "running": false }, { "path": "dist/index.js", "limit": "150 ms", "running": true // Includes parse + eval time } ] }

Lighthouse CI Assertions

Timing budgets require running Lighthouse against the built application. Lighthouse CI provides assertion-based enforcement where specific metric thresholds trigger build failures.

// lighthouserc.js — assertion configuration module.exports = { ci: { assert: { assertions: { // Timing budgets 'largest-contentful-paint': ['error', {maxNumericValue: 2500}], 'cumulative-layout-shift': ['error', {maxNumericValue: 0.1}], 'total-blocking-time': ['error', {maxNumericValue: 300}], // Size budgets via resource-summary 'resource-summary:script:size': ['error', {maxNumericValue: 175000}], 'resource-summary:stylesheet:size': ['warn', {maxNumericValue: 50000}], 'resource-summary:third-party:size': ['error', {maxNumericValue: 100000}], // Quantity budgets 'resource-summary:third-party:count': ['warn', {maxNumericValue: 10}], 'dom-size': ['warn', {maxNumericValue: 1500}] } } } };

PR-Level Reporting

Integrate budget checks with pull request workflows so authors see the impact of their changes before reviewers even look at the code. GitHub status checks, GitLab CI reports, and PR comments that show delta from baseline give authors immediate feedback. A comment showing "JavaScript: +23 KB (new total: 182 KB / 170 KB budget — EXCEEDED)" tells the author exactly what to fix and how far they are from compliance.

Distinguish between "error" (blocks merge) and "warning" (notifies but allows merge) severity levels. Start with warnings for new budgets to build awareness without blocking deployments. Upgrade to errors after the team has stabilized within budget limits for two to three sprints.

Team Adoption and Culture

Communicating the Why

Engineers resist performance budgets that feel arbitrary. Connect budgets to business outcomes: a 100ms improvement in LCP correlates with a measurable increase in conversion rate; every 50 KB of JavaScript adds approximately 250ms of main-thread blocking on mid-tier mobile devices; pages exceeding 3 seconds LCP lose a quantifiable percentage of users before the page becomes interactive.

Frame budgets as a shared commitment rather than a restriction. The budget exists because every team member's changes share the same byte and millisecond allowance. Without it, one team's analytics package consumes the headroom another team needs for a feature.

Budget Exception Process

A rigid budget without an exception process breeds resentment and workarounds. Define a clear process for budget increases: the requesting team documents what they are adding, why it exceeds the budget, what optimizations they attempted, and what the expected business impact is. The performance team or tech lead approves or suggests alternatives. Approved exceptions are documented and scheduled for future optimization.

Gradual Tightening

Start with budgets that the current codebase passes. Tighten quarterly based on optimization work completed. A JavaScript budget that starts at 180 KB might tighten to 160 KB after the team completes a code splitting initiative, then to 140 KB after migrating from a monolithic framework import to modular imports. Each tightening step should follow a completed optimization effort, not precede it.

Budget Evolution and Maintenance

Page-Specific Budgets

Not all pages deserve the same budget. A landing page needs aggressive timing budgets because first impressions drive bounce rate. A complex dashboard with charting libraries legitimately requires more JavaScript than a content page. Define budget tiers aligned with page types: marketing pages (strictest), content pages (moderate), application pages (relaxed but still bounded), and internal tools (bounded but generous).

Monitoring Budget Health

Track budget utilization over time using a dashboard that shows current values against limits for every monitored metric. This reveals trends that individual budget checks miss: a metric that was at 60 percent of budget three months ago and is now at 90 percent is about to breach even though every individual check has passed. Trend monitoring enables proactive optimization rather than reactive firefighting.

Correlate budget metrics with business analytics to validate that budget improvements translate to user experience improvements. If tightening the JavaScript budget from 180 KB to 140 KB did not measurably improve interaction metrics in the field, the budget was not targeting the right bottleneck.

Third-Party Budget Management

Third-party scripts deserve their own sub-budget because they are the most common source of budget breaches. Marketing teams add analytics pixels, customer success teams add chat widgets, and product teams integrate A/B testing frameworks — each individually small but collectively massive. A third-party byte budget with a named owner creates accountability. Every new third-party script must fit within the budget; adding one means removing or optimizing another.

Beware of third-party scripts that load additional sub-resources. A 5 KB tag manager script might dynamically load 200 KB of additional JavaScript. Measure the total cost of each third-party integration, not just its initial script size. Use third-party performance analysis to audit the full impact.