A performance budget is a short list of limits a website agrees not to exceed, such as total page weight, number of requests, JavaScript size, and time to the largest paint. You set it from a measured baseline, check it automatically on every change, and treat going over as a bug to fix before release.
Scroll to the bottom of this page and the footer will tell you what it cost you to load: how many requests, how many kilobytes, how long until it finished painting, and how many elements are in the document. Those figures are not typed in. They are measured in your browser, on your connection, a moment after the page loads.
We put that there for two reasons. It keeps us honest, because a slow page would say so in public. And it turns a vague intention, "keep the site fast", into numbers somebody can see change.
That is all a performance budget is. This post covers how to set one, how to enforce it, and the code behind our footer.
What is a website performance budget?
A website performance budget is a written set of limits on what a page may cost a visitor: how many bytes it downloads, how much JavaScript it runs, and how long it takes to show its main content. Any change that pushes a page over a limit is treated as a defect.
The reason to write it down is that sites do not get slow in one decision. They get slow one reasonable request at a time: a chat widget, a second font, a carousel, a tag for a campaign that ended last year. Each one is small. Without a limit, nobody is ever the person who says no.
A budget changes the question. It stops being "is this script worth having" and becomes "what are we removing to make room for it". For the underlying causes of slowness, see what makes a website fast.
What should a performance budget measure?
A useful budget measures a small number of things you can check automatically. The common ones are total transfer size, request count, JavaScript size, and the time to Largest Contentful Paint, which is the moment the biggest visible element finishes rendering.
| Metric | What it tells you | How to check it |
|---|---|---|
| Total transfer size | What the page costs on a metered or slow connection | Browser network panel, or the Resource Timing API |
| Request count | How many round trips the page depends on | Same sources as transfer size |
| JavaScript size | How much code the device must parse and run | Build output, file sizes |
| Largest Contentful Paint | When the main content is visible | Lab tools and real visitor measurement |
| Element count | How heavy the document is to lay out and style | document.getElementsByTagName('*').length |
Quantity limits, such as bytes and requests, are the easiest to enforce because they barely vary between runs. Timing limits vary with the device and network, so set them against a named test condition, for example a mid-range phone on a throttled connection. Google's published threshold for a good Largest Contentful Paint is 2.5 seconds, which is a reasonable outer limit, not a target to aim at.
How does our footer measure the page?
Our footer uses three browser APIs that every page already has access to. The Navigation Timing and Resource Timing APIs report each file the page loaded and its size. A PerformanceObserver reports the Largest Contentful Paint. A short function adds them up and writes one sentence.
This is the code from our site script, with the output string shortened:
let lcp = 0;
try {
new PerformanceObserver((l) => { for (const e of l.getEntries()) lcp = e.startTime; })
.observe({ type: 'largest-contentful-paint', buffered: true });
} catch {}
const report = () => {
const nav = performance.getEntriesByType('navigation')[0];
const res = performance.getEntriesByType('resource');
const bytes = [nav, ...res].reduce((n, e) => n + (e?.transferSize || e?.encodedBodySize || 0), 0);
const kb = bytes / 1024;
const paint = lcp || nav?.domContentLoadedEventEnd || 0;
tele.innerHTML = /* requests, weight, paint time, element count */;
};
addEventListener('load', () => setTimeout(report, 1800));
The request count is the number of resource entries plus one for the document. The weight is the sum of transferSize across all of them. The paint time is the last Largest Contentful Paint entry the browser reported. The whole thing waits 1.8 seconds after the load event so late entries have a chance to arrive.
Nothing is sent to us. The numbers are shown to the visitor and discarded.
How accurate are browser-side measurements?
Browser-side measurements are accurate about what happened on that one visit, and that is both their value and their limit. They reflect the visitor's real device, cache, and network. They are not a controlled test, so two visits to the same page can honestly report different numbers.
We would rather list what our own footer gets wrong than have you find out:
- Cached files. A file served from the browser cache reports a
transferSizeof zero. Our code then falls back toencodedBodySize, so on a repeat visit the figure is closer to the weight of the files than to the bytes that crossed the network. - Late requests. Anything loaded after the report runs, such as an image lazy-loaded further down, is not counted.
- Missing paint data. Where a browser does not report Largest Contentful Paint, the code falls back to the end of
DOMContentLoaded, which is a rougher number. - Prerendered pages. We prerender the next page with speculation rules. Our code does not subtract the activation time, so on a prerendered page the paint figure is counted from when the background load began.
- Two fixed claims. The sentence ends by saying no frameworks and no trackers were loaded. Those are statements about how the site is built, not measurements.
One thing does work in our favour. Sizes for files on other domains are hidden unless that server allows it, and every file on this site is served from our own domain, so nothing is missing for that reason.
How do you set a performance budget?
Set a budget from where the site is now, not from an ideal. Measure the key pages, decide which numbers matter for your visitors, set limits slightly tighter than today's values, and write them where the whole team will see them. A budget nobody can meet gets ignored.
- Pick three to five page types: home, a service page, a blog post, the contact page.
- Measure each one under a fixed test condition and record weight, requests, JavaScript size, and Largest Contentful Paint.
- Set limits a little under the current numbers, or at the current numbers if they are already good.
- Write the limits down next to the code, not in a slide deck.
- Decide in advance what happens when a change goes over: it is fixed, or something else is removed.
We are not going to print our own figures here, because the footer already prints the real ones for the page you are reading.
How do you enforce a performance budget?
A budget is enforced by checking it automatically and often. The cheapest check runs at build time and fails when a file grows past its limit. Lab tests catch timing regressions before release. Measurement from real visitors tells you whether the lab was right. Use at least the first.
How hard this is depends on the kind of site. A static site is the easy case: there is no server work per request and nothing loads that the build did not put there. The 305 pages we built for Gayer Law are static files for that reason.
A content management system is harder, because weight arrives from more directions: the theme, each plugin, and whatever marketing adds later. Our work on Tamou Law Group, a WordPress site, included a dedicated mobile performance pass. On that kind of site a budget has to cover third-party scripts explicitly, since they are the part the developers do not control.
Frequently asked questions
What is a good page weight for a small business website?
There is no single correct number, and we will not invent one. Lighter is better for visitors on phones and slow connections. Measure your own key pages, compare them with how they feel on a mid-range phone, and set the limit from there.
Is a performance budget the same as Core Web Vitals?
No. Core Web Vitals are specific measurements Google defines for loading, responsiveness, and visual stability. A performance budget is your own set of limits, which can include those measurements along with things they do not cover, such as total weight and request count.
Who should own the performance budget?
One named person, usually the lead developer, with the business owner's backing. The budget only works if someone can refuse an addition or ask what will be removed to make room, and has the authority to be listened to.
Do images count toward the budget?
Yes. Images are often the largest part of a page. Serve modern formats, size them for the layout, and lazy-load the ones below the first screen.
If you want to know what your site costs its visitors and where the weight is, send us the address.