What is a performance budget, why do most attempts at one fail, and how should it be enforced so it actually constrains behaviour?
Show the full answer Hide the answer
What it is and why it exists
A performance budget is a stated limit on a performance characteristic — p99 latency for an endpoint, JavaScript bundle size, database queries per request, time to interactive — that is enforced automatically and blocks a change that breaches it.
It exists because performance degrades by accumulation. No single change makes a system slow; each adds a few milliseconds, each is individually defensible, and after two years the page takes four seconds. Without a budget there is no moment at which anyone is required to say no, and the degradation is nobody's decision.
Why most attempts fail
- The budget is aspirational rather than current. A budget set below current performance is breached immediately, so it is disabled or ignored within a week. Set it at current performance and ratchet down.
- It is not enforced in the pipeline. A dashboard that someone might look at is not a budget; the gate is the mechanism.
- Measurement is too noisy to gate on. Latency measured on shared CI runners varies enough that a real regression is indistinguishable from noise, so the gate produces false failures, and false failures are disabled. Deterministic proxies — query counts, bundle bytes, allocation counts — are far more gateable than wall-clock time.
- No owner. A breach with no owner is a broken build that someone bypasses.
- The budget covers the wrong thing — a synthetic benchmark rather than the user journey that matters.
- No exception process, so a legitimate breach is handled by deleting the check.
How to enforce it properly
- Measure what users experience, and gate on it where it is stable enough: field data for trends, lab or synthetic data for gating.
- Prefer deterministic metrics for the hard gate: bytes shipped, number of queries, number of network round trips, allocations. These are exactly reproducible, so a change either breached the budget or did not.
- Ratchet: the budget is set at today's value and tightened when it improves, so performance is a one-way door.
- Fail the build, with a clear message showing the previous value, the new value and the limit.
- A documented, time-boxed exception requiring an owner and a follow-up issue — because a gate with no exception process gets deleted the first time it is genuinely wrong.
- Budget per journey, not per component, so the total is owned rather than each part being individually innocent.
- Continuous field monitoring alongside, because lab measurements miss real-device and real-network behaviour entirely.
The organisational part
Performance budgets work when a breach is a normal, expected event with a routine response — investigate, fix, or take a documented exception. They fail when a breach is an emergency, because emergencies are resolved by removing the obstruction.
The budget's real function is to make the trade-off explicit at the moment it is made, by someone who knows why the change is worth the cost — rather than leaving it to be discovered by users two years later, when the cause is untraceable and the fix is a rewrite.