Performance Budgets That Stick

Editorial Team

Overview

Performance budgets are constraints on page weight, loading time, or Lighthouse scores that the team commits to maintaining. Without them, performance degrades by default: every added dependency, third-party script, and marketing pixel is individually defensible but collectively ruinous.

Key takeaways

  • A performance budget is a constraint, not a goal — exceeding it fails the build.
  • Budgets should be set from user research and competitor analysis, not wishful thinking.
  • Automated enforcement in CI is the only kind that works long-term.
  • Budgets must be reviewed and updated as product requirements evolve.

Why budgets degrade without enforcement

Adding 20 KB to a page feels harmless in isolation. Done ten times in a sprint, it doubles the page weight. The mechanism is well-understood: each decision is made locally by the person closest to it, without visibility into the cumulative effect. A budget externalizes that cumulative effect into a shared constraint visible to the whole team.

Setting a realistic budget

A budget that is already violated at launch is worse than no budget — it signals that the constraint is decorative.

Reference points for budget-setting

  • Your current state — measure the page before adding a budget; the budget must allow the page to pass today
  • Competitor baselines — measure the 50th-percentile performance of 3–5 competitors using WebPageTest; your budget should match or beat them
  • User research — 53% of mobile users abandon pages that take longer than 3 seconds to load; align budgets with the connection speeds of your target audience
  • Core Web Vitals — Google's LCP, INP, and CLS thresholds are widely accepted baselines and affect search ranking

Recommended starting budgets

Metric Target
Largest Contentful Paint (LCP) ≤ 2.5 seconds
Interaction to Next Paint (INP) ≤ 200 ms
Cumulative Layout Shift (CLS) ≤ 0.1
Total page weight ≤ 500 KB (transferred)
JavaScript bundle ≤ 150 KB (parsed + executed)
Third-party scripts ≤ 2 synchronous, all others deferred

Adjust based on your product's specific context — a data-heavy dashboard has different constraints than a marketing landing page.

Enforcing budgets in CI

A budget documented in a README is aspirational. A budget enforced in a CI pipeline is a constraint.

Lighthouse CI

Lighthouse CI runs Google Lighthouse audits on every pull request and fails the build when scores fall below defined thresholds.

# .lighthouserc.yml
ci:
    collect:
        url:
            - http://localhost:3000/
    assert:
        preset: lighthouse:recommended
        assertions:
            largest-contentful-paint:
                - error
                - maxNumericValue: 2500
            total-byte-weight:
                - error
                - maxNumericValue: 512000

Bundlesize / size-limit

For JavaScript budgets, tools like size-limit check the final bundle at build time:

// package.json
"size-limit": [
  {
    "path": "dist/assets/js/main.js",
    "limit": "150 kB"
  }
]

A failed size check blocks the merge — the developer must either optimize the code or update the budget with explicit justification.

Keeping budgets visible

Automated enforcement handles regressions, but budgets should also be visible in day-to-day work.

Dashboard integration

Add a performance dashboard (Lighthouse CI's dashboard, SpeedCurve, or a self-hosted alternative) to your team's internal tooling. Graphs showing score trends over time make degradation visible before it becomes a problem.

Pull request annotations

Configure CI to post budget results as PR comments. Developers see the performance impact of their changes during review, not after merge.

When to update a budget

A budget is not immutable. Review it when:

  • A major new feature requires capabilities that cannot be delivered within the current budget
  • The product's target audience changes (new device or network demographics)
  • Web standards evolve and what was acceptable is no longer competitive

When a budget is updated, document the reason and the tradeoff. "We increased the JS budget from 150 KB to 200 KB to support the new rich text editor; we offset this by deferring analytics scripts" is a healthy change. "We removed the budget because it kept failing" is not.

Common budget mistakes

  • Measuring only in ideal conditions — always measure on throttled connections simulating real users
  • Exempting third-party scripts — third-party tags are often the biggest contributors to weight; they must be in scope
  • Setting budgets per-page but shipping shared bundles — measure the total loading experience for a first-time visitor, including shared dependencies
  • Never reviewing the budget — products change; budgets that don't evolve with them become obstacles

Conclusion

A performance budget that is set realistically, enforced automatically, and reviewed regularly is one of the most effective quality tools available to a web team. The engineering overhead is low; the protection against gradual degradation is high.

More resources