Next.jsJuly 31, 2026 · 9 min

Fixing Core Web Vitals in Next.js: a performance playbook that moves conversions

Every second of load time costs signups and checkouts — that's measured, not folklore. Core Web Vitals put numbers on it: LCP (how fast the main content appears), CLS (how much the page jumps), INP (how quickly it responds to input). Here's the Next.js playbook I actually run to move all three, and why each one is a business lever.

LCP: get the main content on screen fast

The largest element above the fold — usually a hero image or headline — should render from the server with no client round-trip. Fetch its data on the server, avoid a client-side spinner-then-content dance for the hero, and preload the LCP image. The killer anti-pattern is fetching above-the-fold data in a useEffect: the user watches an empty box while the browser does a second trip.

// Prioritize the LCP image; size it so nothing shifts
import Image from 'next/image';
<Image src={hero} alt="" priority sizes="100vw"
  width={1600} height={900} />   // priority preloads it; dims reserve space

CLS: reserve space for everything

  • Always give images explicit width/height or an aspect-ratio so the layout doesn't jump when they load.
  • Reserve space for ads, embeds and late-loading banners with a min-height placeholder.
  • Load fonts with next/font and a size-adjusted fallback so text doesn't reflow when the webfont swaps in.
  • Never insert content above existing content after load — it shoves everything down and spikes CLS.

INP: keep the main thread free

Interaction latency comes from shipping too much JavaScript. In the App Router the win is architectural: server components by default, and 'use client' only on the leaves that truly need interactivity. That keeps the hydrated bundle small, so taps and clicks respond immediately instead of waiting behind a long JS task.

The most common Next.js performance mistake isn't a missing optimization — it's making everything a client component. Server-first is the single biggest lever on both bundle size and INP.

Bundle discipline

Audit what you ship: a bundle analyzer surfaces the heavy third-party dependency doing little (a giant date or icon library, a charting lib pulled in eagerly). Dynamically import below-the-fold and rarely-used components so they're not in the initial payload, and prefer lighter alternatives for the big offenders. Every kilobyte the browser parses is INP you're spending.

Measure real users, not just the lab

Lighthouse is a lab signal; Google ranks on field data (CrUX) from real devices and networks. Wire up real-user monitoring so you see p75 LCP/CLS/INP for actual visitors — the lab can look green while users on mid-range phones suffer. Optimize for the field numbers.

Key takeaways

  • LCP: render the hero server-side and preload its image; never fetch above-the-fold data client-side.
  • CLS: reserve space for images, embeds and fonts so nothing jumps.
  • INP: server components by default, 'use client' only at interactive leaves.
  • Trim the bundle with analysis + dynamic imports, and optimize against real-user field data.

FAQ

Why is my Next.js LCP slow even though the site feels fast?

Usually the above-the-fold content is fetched on the client (in useEffect or a client component) instead of rendered on the server, so the browser makes a second round-trip before the main content appears. Render the hero and its data on the server and preload the LCP image with priority.

Do Core Web Vitals actually affect rankings and revenue?

Yes to both. They're a confirmed Google ranking signal, and independent studies consistently tie faster load and lower layout shift to higher conversion. A CWV fix is a growth task, not a vanity score — treat p75 field data as the target, not just the Lighthouse lab number.

AA
Ali Asghar

Senior software engineer & technical lead — 6+ years shipping production multi-tenant SaaS, payments and AI integration in Next.js, Node & TypeScript.

Keep reading
The Next.js technical SEO checklist for SaaS that actually ranksWhat actually matters running the Next.js App Router in production