A website that has to stay fast.

Almost every website is fast on launch day. It gets slow afterwards: a little more with every new script, every image and every feature, until someone notices. That is why this website has fixed limits that are measured before every release. If a page exceeds them, the version does not go live. This case study shows how that is built and what you can take away for your own product.

Starting point

Performance is rarely lost through a single decision. Every change costs a few milliseconds and a few kilobytes, and none of them stands out on its own. Without a fixed limit there is no moment when someone says stop.

Solution

Three limits for loading time, layout and page weight are kept in one file. Before every release, the pipeline loads every type of page in a real browser and measures it against them.

Result

The limits are considerably stricter than what Google rates as good, and every type of page meets them. If a page gets too slow, that shows before the release and not only to the visitors.

Performance budgets in brief

A performance budget is an upper limit a page must not exceed while loading, much like a cost budget in a project. The difference from a good intention: the limit is a number, and it is checked automatically. Nobody has to remember it, and nobody has to argue about it.

What gets measured is what visitors feel. Google sums this up in the Core Web Vitals. Two of them can be measured directly while a page loads: Largest Contentful Paint (LCP) tells when the largest visible content is in place, Cumulative Layout Shift (CLS) how much the layout still jumps while it does.

On top of that comes the transfer size, the amount of data a page transfers while loading. It is not one of Google’s metrics, but it is the earliest warning: a page almost always gets heavier first and slower second. On a mobile network, every kilobyte counts as well.

Three limits, one file

LCP ≤ 1.2 s

Loading time

This is how long it may take at most until the largest visible content of a page is in place. Google rates up to 2.5 seconds as good, the limit here is considerably tighter.

CLS ≤ 0.02

A calm layout

This is how little the layout may shift while loading. Nothing should jump away while someone is reading or about to click. Google rates up to 0.1 as good.

Transfer ≤ 200 kB

Page weight

This is how much a page may transfer at most while loading, including HTML, CSS, JavaScript, fonts and images. This limit is the first to trip when a new dependency is added.

How the page stays light

  1. Finished HTML from the server

    The server delivers every page as finished HTML, written in Go with templ. The browser does not have to start an application before content appears. That is the main reason for the short loading time.

  2. One CSS file, one JavaScript file

    All styles are in one minified file, all JavaScript in a second one. htmx is enough for interactions, without a frontend framework. There are no third-party scripts apart from the analytics, and those load without holding up the page.

  3. Graphics that are drawn

    The animated graphics of the solution pages and case studies are not images or videos. The same script draws them in the browser on a canvas. A new graphic therefore costs a few lines of code instead of another image file. Their space is reserved from the start, so nothing shifts.

  4. Font and cache

    The font is served from the website’s own server, as one variable file for all weights, and is preloaded. All files are delivered compressed and carry the version of the build in their address. The browser may therefore keep them for a long time and still fetches them anew after a release.

How the budget is enforced

A budget nobody checks is a statement of intent. That is why it is not a person measuring now and then, but the pipeline at every release, with Playwright and the measuring points of the browser.

One source for the limits

The three numbers are kept in exactly one place. The tests read them from there, and so do the cards on this page and on the solution page. What you see here is what is actually measured against.

Measured in a real browser

The pipeline loads every type of page in Chromium: home page, overview, solution page, case study and the rest. It measures as soon as the fonts are loaded and no request is pending.

A gate before the release

Every version first runs on a staging environment. Only when all tests pass there does exactly this version go live. If a page breaks a budget, the old version stays online.

Fair and visible measurement

Because many tests run at the same time, the best of three attempts counts for the loading time: load on the machine can delay a measurement but never speed it up. The measured values of every page appear in the summary of the run. That way a trend shows before it becomes a problem.

Why a budget matters even more with AI

With AI agents, code is written faster than ever, and so is everything that makes a page heavy. An agent delivers what works and likes to bring along one more library, image or script. It does not check on its own what that costs in loading time. And with many changes a day, nobody reads every line closely enough to notice.

A budget in the pipeline catches exactly that: it measures every change, no matter who wrote it. That lets a team keep developing quickly with AI without the application getting slower unnoticed. It is how I work myself: AI implements, the budget checks, I decide. Because no agent sets the limits: which metrics matter for this product, how strict can the limit be, and what has to go when it breaks? That is a trade-off between users, product and effort, and that is the experience I bring. More on the page Speed up your web app.

What you can take away for your product

  1. Measure first, then set the limit

    Measure where you are today and set the budget just above it. That way it is met from day one and keeps things from getting worse. You can tighten it with every optimization.

  2. A few numbers everyone understands

    Three limits are enough. Nobody maintains a long list of metrics, and when in doubt nobody knows which of them matters.

  3. The budget must be allowed to stop a release

    A warning in a report gets overlooked. Only when exceeding the limit stops the release do people talk about performance before the users feel it.

Documentation for further reading

Performance budgets

The introduction on web.dev and how to build budgets into your build.

Measuring in the browser

Playwright for tests in a real browser and the PerformanceObserver that provides the measured values.

The technology of this website

The HTML comes from the server with templ. CSS and JavaScript are written by hand, without a framework. The only external dependency is htmx for interactions, and it ships inside the site’s own script.

Frequently asked questions

Do we need a budget if the application is fast today?

Especially then. A budget makes nothing faster, it holds the level. Introducing it costs the least while the values are good.

What happens when an important feature breaks the budget?

Then there is a deliberate decision instead of an accident: build the feature leaner, save somewhere else or raise the budget. All three are fine as long as someone makes the decision.

Does this work with React, Angular or Vue as well?

Yes. The budget measures in the browser what reaches the user, regardless of the technology behind it. The limits for a large application differ from those of this website, the principle is the same.

How do I find out where our application stands?

In the fixed-price performance audit I measure your application under realistic conditions. You learn which causes account for the largest share and which limits make sense for you.

Let's talk about your situation

In a free initial call we take a look at your problem together. You get an honest assessment of whether and how I can help.

The matching solution