Skip to content
Back to portfolioLet's talk
PerformanceUpdated 6 min read

Shipping 95+ Lighthouse Scores in Next.js

Hit 95+ Lighthouse in Next.js with server rendering discipline, image and font wins and CI budgets for Core Web Vitals.

KA

Khizar Ahmed

Full-Stack MERN & AI Automation Engineer · Lahore, Pakistan

A 95+ Lighthouse score isn't a vanity metric — Core Web Vitals are a ranking signal and a proxy for how fast the experience actually feels. In Next.js the wins are well understood; you just have to apply them consistently.

Which rendering strategy fits which page?

Match the strategy to how often content changes and who writes it:

  • Static (SSG) for marketing pages and blog posts — fastest possible delivery, zero server cost per view.
  • Incremental Static Regeneration for pages that change occasionally — product listings, docs, portfolio case studies.
  • Streaming SSR for personalised shells — send the static frame instantly, stream user-specific widgets as they resolve.
  • Pure client rendering only where data is genuinely real-time and behind auth — dashboards, editors.

Which mistakes keep Next.js scores low?

  • Marking a whole page 'use client' because one widget needed state — the entire page's JS then ships to the browser.
  • Raw <img> tags without dimensions, causing layout shift that destroys CLS after hydration.
  • Third-party chat/analytics widgets loaded synchronously in <head>, stalling first paint for everyone.
  • Fetching data in useEffect on mount instead of on the server — waterfall requests plus a spinner users actually see.
  • Importing icon/UI libraries through barrel files so hundreds of unused components ride along in the bundle.

None of these are exotic — they're defaults that crept in under deadline. The fix is architectural hygiene enforced by review: a one-line PR checklist ('new client component? new image? new third-party script?') catches every item above before it merges.

Why render on the server by default?

Server Components ship zero JavaScript for everything that isn't interactive. Keep 'use client' at the leaves of the tree — a single button, a carousel — not at the top of a page, so the bulk of your UI stays static HTML.

How do you win LCP with images and fonts?

  • Use next/image with explicit dimensions to reserve space and kill layout shift (CLS).
  • Mark the hero/LCP image priority so it isn't lazy-loaded.
  • Self-host fonts with next/font and font-display: swap to avoid invisible text and network round-trips.
import { Inter } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
});

How do heavy animations hurt real users?

Heavy animation and 3D can tank performance on mid-range devices. Cap device pixel ratio, lazy-load WebGL canvases below the fold, and honor prefers-reduced-motion so the experience degrades gracefully.

Performance is a feature you ship every release — measure it in CI, not once before launch.

What should you measure, and where?

  • Lab data in CI: run Lighthouse on every deploy preview with budgets for LCP, CLS and total JS; fail the build on regression.
  • Field data from users: INP only shows up in real-usage data (Chrome UX Report or your RUM snippet) because it depends on actual interaction.
  • Bundle size per route: track the client-component share of each page — growth there is the earliest warning of future INP problems.

The workflow that keeps scores high is unglamorous: measure before refactoring, ship one change at a time, re-measure, and encode every hard-won win as an automated budget. Teams that skip the last step watch their 98 drift back to 84 within two quarters.

One caveat worth internalising: lab scores and field experience diverge most on interaction metrics. A perfect Lighthouse run says nothing about how long a real checkout button takes to respond on a three-year-old Android — only RUM (or CrUX once your traffic qualifies) captures that. Treat the lab as your regression net and the field as your ground truth, and investigate the moment they disagree.

Wire Lighthouse into your pipeline with a budget, and regressions get caught in review instead of by users.

Frequently asked questions

Why does a high Lighthouse score matter for SEO?
Core Web Vitals are a Google ranking signal and a proxy for how fast a page actually feels. Slow pages leak conversions and impressions — especially on mobile connections where most first visits happen.
Where do I put 'use client' in a Next.js App Router app?
At the leaves of the component tree — a single button, carousel or form — never at the top of a page. Everything that doesn't need interactivity stays as a Server Component shipping zero JavaScript.
How do I stop images from destroying my LCP?
Use next/image with explicit dimensions to prevent layout shift, mark only the hero image as priority so it isn't lazy-loaded, and serve modern formats. Reserve space for everything above the fold before it loads.
Should fonts be loaded from Google Fonts at runtime?
No. Self-host them with next/font so they're bundled with your deploy, use font-display: swap to avoid invisible text, and subset to the character ranges you actually need.
Next.jsPerformanceCore Web VitalsSEO

Have a project like this in mind?

I help teams design and ship MERN, SaaS, ERP and AI products. Let's talk about yours.

Let's talk