Project 3

Cutting a page load from nine seconds to under two

Project 3 was a content site with a real audience and a real problem: on a mid-range phone over a normal connection, the largest element took about nine seconds to appear.

The team had a long list of things they had read they should do. What they did not have was any idea which of them mattered here.

Placeholder image for Project 3

Next.js, Cloudflare, Lighthouse CI

Measuring before deciding

We put real-user monitoring in place and waited a week. That week reordered the entire list.

The two things everyone expected to be the problem — bundle size and the number of requests — were not in the top five. The actual causes were duller:

  • A web font loading without a fallback, which delayed all text.
  • Hero images served at full desktop resolution to phones.
  • A third-party analytics script that blocked rendering.
  • A database query on the homepage that had lost its index during a migration nine months earlier.
Everything we guessed was wrong, and everything the data said was boring.

The work

Four changes, none of them clever. Give the font a metric-compatible fallback and swap it in. Serve responsive image sizes. Load the analytics script after paint. Restore the index.

Placeholder image

Total effort was around three weeks, most of which went into the image pipeline. The database index took eleven minutes and accounted for nearly a third of the improvement.

Keeping it fast

The important part was the last week: a performance budget in continuous integration that fails the build if the largest contentful paint regresses past a threshold.

Without that, the site would have drifted back. Sites always drift back, because every individual addition is small and reasonable.

Result

Largest contentful paint went from around 8.9 seconds to 1.8 on the reference device. Bounce rate on the homepage fell by 22%, and the pages per session figure went up for the first time in two years.