Search and performance

Core Web Vitals on Next.js: a guide for small business sites

How to pass Core Web Vitals on a Next.js site: LCP image, fonts, third-party scripts, layout shift, INP and caching, with the thresholds and how to measure.

Long-exposure red and white light trails streaking past a 40 mph speed limit sign on a dark road at night
On this page
  1. What are the Core Web Vitals thresholds?
  2. How do you get a fast LCP image in Next.js?
  3. What should you do about fonts?
  4. How do third-party scripts hurt, and how do you control them?
  5. How do you stop layout shift?
  6. What do INP and long tasks have to do with it?
  7. Does caching and static rendering matter?
  8. How do you measure it properly?
  9. When this is not for you
  10. What should you do next?

What are the Core Web Vitals thresholds?

There are three, and web.dev says a page passes when it meets all three at the 75th percentile of page loads, split by mobile and desktop. At the time of writing (2026-10):

  • LCP (Largest Contentful Paint): 2.5 seconds or less is good; above 4.0 seconds is poor.
  • INP (Interaction to Next Paint): 200 milliseconds or less is good; above 500 milliseconds is poor.
  • CLS (Cumulative Layout Shift): 0.1 or less is good; above 0.25 is poor.

LCP is about how fast the main content shows. INP is how quickly the page reacts after a click, tap or key press. CLS is how much the layout jumps around. Next.js gives you good defaults for several of these, but defaults do not pass the test for you. The rest of this post goes through where a typical small business site loses points, in the order we would check.

How do you get a fast LCP image in Next.js?

Start with the largest thing above the fold, usually a hero image or a heading with an image. web.dev's guidance on LCP is blunt: never lazy-load the LCP image, make sure it is discoverable in the initial HTML, and give it high fetch priority. It also says most of the LCP time should go to loading the HTML document and the LCP resource itself.

In Next.js this means:

  1. Use next/image for that image, with width and height (or a static import). Next.js uses these to reserve space and serves correctly sized, modern formats.
  2. Mark it as important. In Next.js 16 the priority prop is deprecated in favor of preload, and the docs add that in most cases fetchPriority="high" or loading="eager" is the better choice. Do not use preload if different images could be the LCP element on different screen sizes.
  3. Set sizes so phones do not download desktop-sized files.
  4. Do not hide it in client-only code. If the image appears only after JavaScript runs, the browser finds it late.

Then check your server's response time. The first part of every LCP is the HTML arriving, so a slow server or a chain of redirects costs you before any image problem does.

What should you do about fonts?

Use next/font. The docs say it self-hosts font files, removes the external network requests, and loads fonts with no layout shift. Two common mistakes to avoid:

  • adding a Google Fonts <link> in addition to next/font, which defeats the point
  • loading six weights when the design uses two

Fewer font files means less to download before text looks right. A font swap that changes text size is one of the named causes of layout shift in web.dev's CLS guide, so check that the fallback and final font do not differ wildly in size.

How do third-party scripts hurt, and how do you control them?

Chat widgets, tag managers, heatmaps and ad pixels run on the same main thread as your page. They affect INP and often LCP too. The Next.js docs recommend loading third-party scripts only on the pages or layouts that need them, and next/script has strategies:

  • afterInteractive (the default): load early, after some hydration
  • lazyOnload: load during browser idle time
  • beforeInteractive: load before any Next.js code, which is rarely right for marketing tools
  • worker: experimental, and the docs warn it does not yet work with the App Router

A practical audit, which takes an hour:

  1. List every script and who asked for it.
  2. Remove the ones nobody can justify.
  3. Move the rest to lazyOnload where the tool still works.
  4. Re-measure.

How do you stop layout shift?

web.dev lists the usual causes: images and videos without dimensions, font swaps, injected content such as ads and embeds, and content that arrives late without reserved space. The fixes follow:

  • give every image and video a width and height or an aspect ratio; next/image does this for you if you give it dimensions
  • reserve space for embeds, banners and cookie notices before they load
  • animate with transform instead of properties that change layout
  • check that late-loading content does not push text down

A cookie banner that pushes the page down when it appears is one of the most common avoidable shifts. Make it overlay or reserve its space.

What do INP and long tasks have to do with it?

INP looks at every click, tap and key press during a visit, and measures the time until the browser can paint the next frame. The usual cause of a bad INP is JavaScript hogging the main thread. web.dev defines a long task as any task over 50 milliseconds, and the fix is to break the work up, use scheduler.yield() where supported, do user-facing work first and defer things like analytics.

For a small business site, the biggest wins are usually boring:

  • ship less client-side JavaScript; keep components as server components unless they need interactivity
  • avoid heavy libraries for small jobs
  • do not run big computations or large list renders inside click handlers
  • remove third-party scripts you do not need

Does caching and static rendering matter?

Yes, because the LCP clock starts when the page request starts. A page that is prerendered and served as static HTML skips the work of rendering on every request. The Next.js docs describe route-level controls: you can force a page to be static, or revalidate it after a number of seconds or on demand after an edit. A typical small business site, whose pages change when someone edits content, fits well: prerender, then revalidate when the content changes.

One caution: the Next.js caching docs vary by version and by whether you use the newer Cache Components model. Read the docs for the version you actually run, and test that an edit appears when you expect it to.

How do you measure it properly?

Measure field data first, then use lab tools to find the cause.

  • Field data comes from real visitors. web.dev says to prioritize it for decisions. INP in particular cannot be accurately measured in a lab, because a lab cannot predict when users will interact.
  • PageSpeed Insights shows both. Its field data comes from the Chrome User Experience Report over a trailing 28 days. If your URL has too little data it falls back to the whole origin, and if that is missing too, you get no field metrics. Its lab data is a Lighthouse test on a simulated device.
  • Search Console has a Core Web Vitals report built on the same field data. It covers indexed URLs only, groups similar URLs, separates mobile and desktop, and Google says it is not designed to show the status of one specific URL.

A new or low-traffic site may have no field data for months. In that case use lab runs as a guide, and do not treat one Lighthouse score as the verdict. Run it several times, test on the key pages, and re-check Search Console once data appears.

When this is not for you

  • If your site gets very little traffic, field data may not exist yet. Fix the obvious problems (a huge hero image, six widgets) and do not chase the last point of a lab score.
  • If your site is built on a platform where you cannot change scripts, images or fonts, most of this does not apply, and a platform change is a bigger discussion.
  • Passing Core Web Vitals will not by itself bring traffic. It removes a handicap. Content and relevance still decide most rankings.
  • If a page already passes all three at the 75th percentile, leave it alone.

What should you do next?

Run your three most important pages through PageSpeed Insights, write down which metric fails, and fix that one first. If you want a second pair of eyes on a Next.js site, or a site built to pass these thresholds from the start, you can book a free call and we will go through it with you.

Frequently asked questions

What are the Core Web Vitals thresholds?

According to web.dev, a page is good when Largest Contentful Paint is 2.5 seconds or less, Interaction to Next Paint is 200 milliseconds or less, and Cumulative Layout Shift is 0.1 or less, measured at the 75th percentile of page loads.

How do I make the main image load fast in Next.js?

Use the next/image component with width and height, make sure the image is in the initial HTML, never lazy-load it, and give it high fetch priority. In Next.js 16 the priority prop is deprecated in favor of preload, and the docs say fetchPriority high or loading eager is the better choice in most cases.

Should I trust the PageSpeed Insights score or Search Console?

Trust field data first. PageSpeed Insights shows real-user data from the last 28 days where there is enough of it, plus a Lighthouse lab test. Search Console reports field data for indexed URLs in groups.

Why does my lab score look good but Search Console says Poor?

Lab tests run on one simulated device and network. Field data comes from real visitors on real devices, and interaction responsiveness cannot be measured accurately in a lab at all.

Planning a website, app or store?

Tell us what you want to build. You get a clear plan, and you own all of the code.

Book a free call