Skip to content

Issue 14PlaybookNo. 010

Web

The 1 MB page budget: how we keep client sites fast long after launch.

Performance decays one plugin and one hero video at a time. The budget, CI checks and review rituals that stop the slide.

Rafael Santos

Partner · Engineering

Published
Updated
Read time
8 minutes
Hands typing on a backlit keyboard in front of a monitor full of code.
FIG. 1 — Budgets live in the codebase, checked on every pull request.Photo: Performative Web Studio
In this article
  1. Why a budget beats a score
  2. How we split the megabyte
  3. Checks that fail the build
  4. The rituals that stop the slide
  5. When the budget is the wrong number
  6. Key takeaways

Most sites are at their fastest on launch day. Then a chat widget arrives, a marketing tag, a hero video, a second analytics tool — and eighteen months later nobody can say when the site got slow, only that it did.

We stopped treating speed as a launch checklist item years ago. Every site we build now ships with a performance budget: a hard ceiling on what a page is allowed to weigh, enforced by the build and reviewed by people. The headline number is 1 MB. This is how it works, and why it holds.

Why a budget beats a score

Lighthouse scores are useful, but they make a poor contract. They move between runs, they depend on the machine running the test, and a score of 92 doesn't tell a marketer whether they can add one more script. A budget does. “This page may transfer 1 MB on first load” is a sentence anyone on the team can understand, check and argue with.

It also tracks what visitors actually feel. Page weight isn't a Core Web Vital, but it drives two of them. Heavy images and render-blocking files push out Largest Contentful Paint; heavy JavaScript ties up the main thread and hurts Interaction to Next Paint. Google's thresholds for a good experience are an LCP of 2.5 seconds or less, an INP of 200 milliseconds or less and a Cumulative Layout Shift of 0.1 or less, measured at the 75th percentile of real visits. Keeping pages light is the cheapest way we know to stay inside them on mid-range phones and patchy connections.

How we split the megabyte

The 1 MB is the total compressed transfer for a typical page on a first visit, before anyone interacts with it. We split it into line items, so that a breach points at a culprit rather than a mystery.

ResourceBudget (compressed)What usually breaks it
HTML50 KBInlined data blobs, page-builder markup
CSS60 KBUnused framework and theme styles
JavaScript300 KBTag managers, chat widgets, sliders
Fonts100 KBToo many weights, no subsetting
Images and media490 KBUncompressed heroes, autoplay video
Our default split for a 1 MB page. We adjust it per template.

Templates differ — a product listing carries more images than a contact page — so we set the budget per template, not per site. Articles and landing pages usually come in well under. The home page is where the fight happens.

Field note · Hero video

A hero video is the fastest way to blow a budget. If the brief needs one, we ship a compressed poster image as the LCP element, load the video after the page is interactive, and skip it entirely when the visitor has Save-Data or reduced motion turned on.

Checks that fail the build

A budget nobody enforces is a wish. We wire ours into continuous integration, so every pull request is measured before it can merge.

  1. Lighthouse CI on key templates.

    Each pull request runs Lighthouse against the home page, a listing page and an article, with assertions on total byte weight, script size, LCP and layout shift. A breach fails the check.

  2. Bundle size limits.

    JavaScript bundles are measured at build time. Any route that grows past its limit needs a reviewer to approve the increase, with the reason written in the pull request.

  3. Image rules in the pipeline.

    Images are resized and converted to modern formats such as AVIF or WebP automatically, with explicit dimensions so nothing shifts while loading. Oversized uploads are rejected, not quietly served.

  4. Third-party scripts behind one door.

    Every external script loads through a single, documented place — usually the tag manager or one component — so the full list is visible at a glance and each one's cost can be measured.

Lab checks catch regressions before they ship. They don't tell you what real visitors experience, so we also collect field data: the web-vitals library reporting into analytics, plus the Chrome UX Report for sites with enough traffic to appear in it. When the two disagree, field data wins.

A laptop on a dark wooden desk showing a dashboard of gauges and charts, with a city skyline at night behind it.
Fig. 2 — The monthly review: field Core Web Vitals, the budget report and every script added since last month, on one screen.

The rituals that stop the slide

Most performance regressions on client sites don't come from developers. They come from reasonable requests: a new pixel for a campaign, a review widget, a pop-up for the sale. So the last layer is process, not tooling.

  • One in, one out. A new third-party script needs a named owner, a reason and an end date. If the page is already at budget, something else has to go.
  • A monthly performance review. Fifteen minutes with the client's marketing lead: field Core Web Vitals, the budget report and every script added since last month.
  • Campaign tags expire. Pixels added for a promotion are removed when the promotion ends, not when someone eventually notices.
  • Guidance for editors. A one-page guide to image sizes, embeds and video, written for the people who publish rather than the people who build.

None of this is clever. It works because it turns performance from a one-off project into a habit with a number attached.

“Sites don't get slow in one release. They get slow one reasonable request at a time — so the budget has to be just as persistent.”

— Rafael Santos, Engineering Partner

When the budget is the wrong number

1 MB isn't sacred. A photography portfolio or a product configurator may need more, and that's fine as long as the trade is explicit: where the extra weight goes, what it buys and how it loads. Interactive tools can load their heavy code only when someone opens them. Galleries can lazy-load everything below the first screen. What we won't accept is weight that arrives by accident.

The opposite happens too. For a landing page that lives on paid traffic, we often set the budget lower: every extra second between the ad click and a usable page is spend you've already paid for. If you'd like a second opinion on where your own pages stand, our web development team runs this audit as a fixed-scope project.

Key takeaways

If you only remember three things

  1. Set a byte budget per template. It's a clearer contract than a Lighthouse score.

  2. Enforce it in CI, and back the lab checks with field data from real visitors.

  3. Most regressions arrive as reasonable requests — give every script an owner and an end date.

  • Core Web Vitals
  • Performance
  • Lighthouse

Share

Portrait of Rafael Santos

Written by

Rafael Santos

Partner · Engineering · 15 years shipping software

Rafael leads engineering across our web, app and CRM projects. He has shipped products on most of the stacks clients ask us about, and writes here about the technical decisions that age well — and the ones that don't.

The monthly build

Get the next essay
in your inbox.

One email a month · 4,200 readers · No spam

Rather we ran this playbook for you?

Plan a web project