Start a project

Article · Web performance · Budgets · 11 min read

How to set a performance budget

A performance budget is a written limit on what a page is allowed to weigh, to request, or to take, so that a new script, font or hero image cannot arrive as a surprise. It is a decision, not a dashboard. The useful version on a small site is a short list of units you can measure in a build, with a name attached to each third party, and a habit of treating a breach as a choice: cut something, or change the budget on purpose.

On this page 10 sections
  1. A budget is a decision, not a dashboard
  2. Pick the units that match the problem
  3. A starter budget for a small marketing site
  4. Third parties, fonts and images
  5. How it relates to LCP, INP and CLS
  6. Measuring and failing a build without theatre
  7. What to do when something will not fit
  8. Reviewing the budget after launch
  9. Key takeaways
  10. Frequently asked questions

I keep budgets for the same reason I keep the scope tight in the iOS app MVP checklist: a number you will actually defend is more useful than a colourful report you ignore. The Performance Budget Calculator and the Performance Budget Simulator are there to help you try the numbers, not to issue a standard.

A budget is a decision, not a dashboard

Teams often start with a lighthouse chart and never write the sentence that would make it a budget: “this page may not ship more than this much JavaScript,” or “this template may not add a fourth third-party tag.” A dashboard will describe yesterday. A budget tells you whether today’s change is allowed.

The decision should be specific enough to fail a build, or to fail a pull request review, without a meeting:

If no one is willing to reject a change, you do not have a budget. You have a hope. That is also how costs behave in what an iOS app really costs: an unspoken ceiling is not a ceiling.

Pick the units that match the problem

Choose a small set of units that describe the failures you actually have, and that you can measure reliably.

Good units for a small site:

Weaker units, if they are the only ones you have:

You can still watch field metrics. You just should not pretend they are a budget you can enforce this afternoon. The gzip Size Estimator is a better friend to a JavaScript ceiling than a once-a-month CrUX snapshot.

A starter budget for a small marketing site

There is no official budget. The following is a starting point I would try for a small marketing or content site — a home page, a few service pages, and articles — not for a rich web app, and not as a universal rule. Measure your current production templates first, then tighten towards something like this rather than inventing a fantasy site you do not have.

For a typical article or marketing template, on a mobile-sized cold load:

Write the numbers down next to a URL you will re-measure. The Performance Budget Calculator can help you convert “a 4G budget in seconds” into a rough byte cap, but the conversion is a model, not a promise about a real network.

If your current page is already twice these figures, do not set the starter numbers as a wall you will fail every day. Set a budget just below today’s size, and a second, lower target you intend to reach in a specific piece of work. A budget that is always red will be ignored.

Third parties, fonts and images

These three categories are where small sites usually blow a budget that their own HTML would have kept.

Third parties (chat, tags, embeds, A/B tests, maps, extra analytics) cost bytes, requests, and often main-thread time on every visit. Add them one at a time, measure them, and give them an expiry. A tag that was “temporary for a campaign” will still be there next year unless someone owns the budget line. If a third party will not run inside the budget, it does not ship, or it ships only on the page that needs it, after the main content.

Fonts look small in a design file and large on a cold load once you include italics, extra weights, and a second family for headings. Subset to the characters you use, prefer a system stack when the brand can bear it, and do not preload five files “just in case”.

Images are often the LCP element and the heaviest bytes on the page. A budget should cap the hero, and it should reject a gallery that dumps desktop originals into a phone-width column. Compression without srcset is only half of the work.

None of this requires a new aesthetic. It requires a no, or a not on this template.

How it relates to LCP, INP and CLS

A budget is a constraint on inputs. Core Web Vitals are outcomes in the field. They are related, and they are not the same thing.

You can pass a byte budget and still fail a vital, for example if the HTML is slow or the LCP image is discovered late. You can also fail a budget and still look green in the field on a fast-origin, low-interaction page, until the next widget arrives. Use the Core Web Vitals diagnosis method when an outcome fails, and use the budget so you are not diagnosing the same third party every quarter.

As of November 2026, the commonly cited “good” field thresholds remain those on web.dev. Confirm them there before you hard-code them into a report. I would still rather gate a build on bytes you control than on a field percentile you cannot see until after deploy.

Measuring and failing a build without theatre

Measure the built assets, on the templates you named, in continuous integration or in a release script:

The Performance Budget Simulator is a place to rehearse “what if we add this script” before the script is in the repository. The gzip Size Estimator will tell you whether a source file is as cheap on the wire as it looks in the editor.

Record the measurement next to the commit. A budget nobody can audit is a slogan. This is the same instrumentation instinct as finding performance problems with Instruments: a number attached to a recording, not a feeling about the page.

Caching is not a substitute for a budget, but a good cache policy stops repeat visits from paying the cold-load cost again. The HTTP caching headers guide covers that part.

What to do when something will not fit

When a change breaks the budget, you have three honest options:

  1. Cut scope. Do not load the chat widget on articles. Subset the font. Replace a heavy carousel with static images. Split a tool so the library stays on the tool page.
  2. Pay for it elsewhere. If marketing must have a tag on the campaign landing page, take something off that page, or accept that the landing page has a looser budget than the articles, written down.
  3. Change the budget, in the same place you keep the original numbers, with a reason and a name. This is allowed. Doing it silently in a pull request that also adds the script is how the budget dies.

What you should not do is disable the check, or switch the measurement to an uncompressed figure that looks smaller, or test a thinner page than the one customers see.

If the work is genuinely valuable and too large, schedule a dedicated reduction (remove an old tag, split a bundle) before or with the addition. Do not hope that a later performance sprint will appear.

Reviewing the budget after launch

A budget should be reviewed when the site changes shape, not only when a check fails:

Write the review down next to the numbers. If the marketing site has become an application, the starter figures above will be wrong, and you will need budgets per template rather than one cap for the whole origin.

The point is not to preserve the first numbers for ever. The point is that any new number is still a decision.

Key takeaways

If you want a second pair of eyes on a small site that has slowly outgrown its own pages, tell me about it.

Frequently asked questions

What should be in a performance budget?

A short list of limits you can measure: typically your own compressed JavaScript and CSS, the LCP image, font files, request counts, and each third-party tag by name. Name the templates the limits apply to, and say what happens when a change exceeds them. Field metrics are worth watching, but they are a poor only unit for a build gate.

How tight should a JavaScript budget be for a brochure site?

As tight as the site will still allow, and almost always tighter than a default framework install. I would start by measuring what you ship today, set a cap that stops it growing, and aim well under 150 KB transferred on a simple marketing template if you can. There is no official figure; a text-led site can live on much less, and should.

How do I enforce a performance budget in CI?

Measure the built artefacts and fail the build when a compressed bundle, a request list, or a named third party exceeds its cap. Those checks are stable. If you also run Lighthouse in CI, give the metrics slack and pin the test profile, so a noisy score cannot become theatre.

Is a performance budget the same as Core Web Vitals?

No. A budget is a constraint on what you ship. Core Web Vitals are field outcomes for loading, interactivity and visual stability. A good budget makes those outcomes easier to keep, but you can still fail a vital with a tidy byte count, and you still need a diagnosis when that happens.

How do third-party scripts affect a budget?

They spend the same bytes, requests and main-thread time as your own code, often on every page, and they are harder to trim later. Give each tag an owner and a line in the budget, load them only where they are needed, and measure them before you agree to add another.

Written by Lee Johnson. Published 10 November 2026.

All articles · Swift A–Z · Apps

Questions, or an app in mind?

Let's bring your ideas to life. Whether you're envisioning a game-changing Apple Watch app or a transformative iOS experience, I'm here to make it happen.

Start a project