NextjsCore Web Vitals

Core Web Vitals

Core Web Vitals are the specific, measurable metrics Google uses to judge whether a page feels fast and stable to a real user. They matter for more than vanity — they are a confirmed ranking signal in Google Search, and they directly correlate with conversion rates and bounce rates on real sites.

The three metrics

Metric

Measures

Good threshold

LCP (Largest Contentful Paint)

Time until the largest visible element (image, block of text) has rendered

2.5s or less

INP (Interaction to Next Paint)

Responsiveness — the delay between a user interaction and the next visual update

200ms or less

CLS (Cumulative Layout Shift)

Visual stability — how much content unexpectedly shifts as the page loads

0.1 or less

Note
INP replaced the older First Input Delay (FID) metric as an official Core Web Vital in 2024. If you see FID referenced in older articles, INP is its modern successor and measures responsiveness more comprehensively.
How Next.js features improve each metric
  • LCP — Server Components and static rendering send meaningful HTML on the very first response instead of an empty shell that waits for client-side JavaScript; streaming with Suspense lets the largest content render as soon as its data is ready rather than waiting on slower parts of the page.

  • CLS — next/image requires width and height (or fill with a sized parent) up front, reserving the exact layout space before the image loads, so nothing jumps when it arrives. next/font self-hosts fonts and sets consistent fallback metrics, avoiding the shift caused by a late-swapping web font.

  • INP — shipping less client-side JavaScript, by defaulting to Server Components and pushing 'use client' to small leaves, keeps the main thread free to respond quickly to user input instead of being blocked by hydration work.

TSX
import Image from 'next/image'

// width/height reserve layout space up front — prevents CLS
export default function Hero() {
  return <Image src="/hero.jpg" alt="Hero banner" width={1200} height={600} priority />
}

TSX
import { Inter } from 'next/font/google'

// Self-hosted at build time, with size-adjusted fallback metrics
const inter = Inter({ subsets: ['latin'] })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}
Measuring your vitals
  • Lighthouse (built into Chrome DevTools) — a lab-based, single-run audit useful during development.

  • PageSpeed Insights — combines lab data with real-world Chrome User Experience Report (CrUX) field data for a URL.

  • next/web-vitals (the useReportWebVitals hook) — lets you capture real user metrics from your own production traffic and send them to your analytics of choice.

TSX
'use client'

import { useReportWebVitals } from 'next/web-vitals'

export function WebVitals() {
  useReportWebVitals((metric) => {
    // send LCP, INP, CLS, etc. from real visitors to your analytics
    console.log(metric)
  })
  return null
}
Warning
Lab data from a single Lighthouse run on a fast dev machine can look great while real users on slower devices and networks have a very different experience. Field data (CrUX, or your own useReportWebVitals collection) is what Google actually uses for ranking, so treat it as the source of truth over local lab scores.
Tip
If you can only fix one thing, start with LCP — it's usually the metric with the biggest, most visible impact, and the fix (a properly sized next/image hero, or streaming the slow part of the page separately) tends to be straightforward.