Treat the score as a budget, not a badge
A Lighthouse run is a snapshot, not a finish line. We pick a small set of budgets - largest contentful paint, total blocking time, layout shift - and hold every change to them in review. When a score drops, that is a signal to look at what shipped, not a reason to chase points.
- Set budgets for images, fonts and third-party scripts before design starts
- Fail the build when the bundle grows past the agreed ceiling
- Test on a mid-range phone profile, not a fast desktop
Images are usually the whole story
On a content site the hero image and the article cover dominate the timeline. We serve them through the framework image component so they arrive at the size the viewport actually needs, in a modern format, with explicit dimensions so nothing jumps as the page paints.
- Ask for the largest source you can get, then let the optimiser downgrade
- Give every image a width and a height, even when it is fluid
- Lazy-load anything below the fold and leave the cover eager
Ship less JavaScript
Content does not need a client bundle. We keep pages on the server, move interaction into the few components that genuinely need it, and pass serialisable data down instead of letting the browser fetch it later.
- Prefer server components for anything that only renders text
- Delay third-party embeds until a reader interacts with them
- Audit the dependency graph before adding a library
Make it a habit
The score holds when the constraints are part of the workflow rather than a one-off clean-up. We review performance in the same pull request as the feature, so nobody has to schedule a rescue later.



