How to set up a performance budget.
A performance budget is a set of numeric limits a page may not exceed — and it becomes a budget only when it lives in a test, not in a document.
The biggest problem of performance work is that the improvement does not last. A round of optimization happens, the metrics recover, and three deployments later everything is back where it was. The cause is not bad intent but invisibility: a library gets added and nobody looks at the total weight.
The budget closes that invisibility. With the limit bound to a test, the overrun shows at deployment time and a debate begins: is this feature worth that many bytes? The debate itself is valuable — in a project without a budget, that question is never asked.
What to measure
Budget items split into two families: resource-based and metric-based. Both should be used together, because they catch different things.
- Resource-based — total JavaScript, total CSS, total images, the number of font families, the request count. Fast to measure; shows the cause directly.
- Metric-based — LCP, INP, CLS, time to first byte. Shows the user experience but not its cause.
- The resource-based advantage — measurable before deployment, without opening a browser.
- The metric-based advantage — it measures what actually matters.
- Together — the resource budget is the early warning, the metric budget the final check.
The resource budget is especially valuable because it is cheap: measuring a file size takes milliseconds and can run on every build. Metric measurement needs a browser, is slow, and runs less often.
Where the number comes from
The budget figure should not be arbitrary, but it does not have to be perfect either. Three derivation methods work.
First, deriving from the target: the target device and target network are set, and the byte amount downloadable in the desired time under those conditions is computed. The soundest method, and the most labor-intensive.
Second, deriving from the current state: today’s value is measured and the budget set slightly below it. The budget then becomes not a goal but a regression guard — and a regression guard is the most valuable kind for most projects.
Third, deriving from the threshold: Google’s good thresholds are taken and a margin left below them. This site’s budget is set that way — the LCP threshold is 2.5 seconds and the budget 1.8; the layout shift threshold is 0.1 and the budget 0.05.
The rationale for the margin is measurement noise and future load: a budget glued to the ceiling breaks at the first small addition, and at that point the decision is rushed. Headroom buys the chance to decide calmly.
The budget is kept below the official threshold so the regression shows before it hits the threshold.
Where it must live
The budget being written in a document guarantees nothing; documents go unread. The budget must live in a test, and that test must run in the deployment process.
On this site the budget items sit in one block of the verification suite: the raw JavaScript size, the layout shift, LCP and the font family count. The suite measures on every run and goes red on an overrun.
The measured values sit under the ceiling: vendor libraries 55.7 kilobytes after gzip, own code 28, the stylesheet 12.4. Roughly 96 kilobytes in total against a ceiling of 150.
One last design decision: a budget overrun must be an error, not a warning. Warnings accumulate and get ignored; errors stop things and force a decision. The test of whether a budget really is one is what happens when it is exceeded.
When the budget is breached
For the budget to work, what happens at the moment of overrun must be decided in advance. Otherwise the first overrun starts a debate, the debate drags, and it usually ends with the budget being raised — at which point the budget is dead.
A healthy rule: the overrun stops the deployment and offers three options. The feature is shrunk, space is freed elsewhere, or the budget is raised consciously and with its rationale. The third is legitimate — as a decision, not as an escape.
- Shrink — is there a way to build the feature with less code?
- Free space — can a no-longer-used library be removed?
- Defer — is the feature needed at first load, or can it arrive on interaction?
- Raise the budget — with a rationale, a record and a measured impact estimate.
- Cancel the feature — the least loved option, and sometimes the right one.
Whether the fifth item is on the table determines whether the budget really is one. In a project where no feature can ever be canceled, the budget is merely a wish.
On this site the budget items live in one block of the suite, and an overrun goes straight to red — an error, not a warning. Warnings accumulate and get ignored; errors stop things and force decisions.
A practical checklist
Turning this page into an audit step, here is what to check in the budget setup. The list is kept short because long lists do not get walked; six items fit in one sitting.
- Are the items numeric — “let’s keep it low” is not a budget.
- Are there both resource-based and metric-based items?
- Where did the number derive from — target, current state or official threshold?
- Was a margin left below the threshold?
- Does the budget live in a test?
- Does an overrun stop the deployment — or only warn?
The sixth item is the single test of whether a budget really is one. Warnings accumulate and get ignored; errors stop things and force decisions.
The test of whether a budget really is a budget is what happens when it is exceeded.
A closing frame: the budget looks like a constraint but works in practice as a decision tool. In a project without one, every new feature is added silently and its cost never discussed; in a project with one, the same feature starts a debate, and that debate usually produces a better solution. The constraint’s value lies less in what it blocks than in the thinking it forces.
There is also a cultural dimension, harder than the technical one: a budget not owned by the whole team looks like an obstacle imposed by one person, and it collapses at the first pressure. Ownership comes from sharing the budget’s rationale — where the number came from, whom it protects, who suffers what when it is exceeded. When those three answers are known, the budget stops being a constraint and becomes a shared standard.