Skip to content
All articles
Performance
Engineering

Performance budgets that survive a roadmap

By Adrian Vasquez · · 7 min read

A budget nobody can fail is a wish. Here is the small set of numbers, checks and habits that kept a 12-screen SaaS app fast for two years.

Abstract dashboard illustration with a gauge, bar charts and waveform lines

Pick numbers you are willing to block a release on

We run three budgets and nothing more: 170KB of compressed JavaScript on first load, LCP under 2.0s on a throttled mid-range Android, and interaction latency under 200ms on the busiest table view. Each one has an owner and a dashboard.

Budgets only work when failing them has a consequence. Ours fail the pull request. That sounds harsh until you notice it removes the negotiation entirely — nobody has to argue for speed in a planning meeting.

Spend the budget on purpose

Charting libraries, date pickers and rich editors are the usual culprits, so they are loaded per route rather than in the shell. Every dependency over 15KB gets a written justification in the PR description; roughly a third of them get replaced by twenty lines of local code instead.

Server work moved to loaders so the client stops waterfalling. Rendering a list of 12,000 rows became virtualised once, in one primitive, so no feature team has to solve it again.

Watch real users, not just lab runs

Lab numbers catch regressions; field data catches reality. We sample Core Web Vitals from production and alert on the 75th percentile, because the median hides exactly the customers who complain.

Two years in, the app has grown from four screens to twelve and first load is 40KB smaller than at launch. Nothing clever happened — the budget simply never stopped being enforced.

Keep reading