How to Improve Next.js Website Performance and Core Web Vitals
Next.js gives you excellent performance tools, and many teams still ship slow sites with it. The framework cannot stop you from loading a two-megabyte hero image, marking every component as client-side, or adding five third-party scripts to the root layout. Improving Next.js website performance and Core Web Vitals means measuring how real users experience loading, responsiveness, and visual stability, then using the framework's rendering, image, font, and script features to fix the specific bottlenecks those measurements reveal.
Quick Answer: Measure field data in PageSpeed Insights or Search Console first. Then keep components on the server, prioritize the LCP image with next/image, load fonts with next/font, defer third-party scripts with next/script, reserve space for media to prevent layout shift, split heavy client code with dynamic imports, and cache or statically render pages wherever data allows.
What Are Core Web Vitals and How Does Next.js Affect Them?
Core Web Vitals are three user-centered metrics Google uses to describe page experience. Largest Contentful Paint (LCP) measures loading: how long until the largest visible element, usually a hero image or headline, renders. Interaction to Next Paint (INP) measures responsiveness: how quickly the page visually responds to clicks, taps, and key presses across the visit. INP replaced First Input Delay as a Core Web Vital in March 2024. Cumulative Layout Shift (CLS) measures visual stability: how much content unexpectedly moves while the page loads.
Google's published "good" thresholds are an LCP of 2.5 seconds or less, an INP of 200 milliseconds or less, and a CLS of 0.1 or less, assessed at the 75th percentile of page loads. That percentile matters: a page is only "good" if most real visitors, including those on slower phones and networks, have a good experience.
Next.js influences each metric through architecture choices. Server rendering and static generation deliver HTML quickly, which helps LCP. React Server Components keep code out of the browser bundle, which reduces main-thread work and helps INP. The built-in image and font components reserve space and optimize assets, which helps CLS and LCP. If you are newer to the framework, our explainer on how Next.js differs from React clarifies which of these capabilities come from the framework rather than from React itself.
One distinction prevents a lot of wasted effort. Lab data comes from a simulated test, such as Lighthouse, on one device and network profile. Field data comes from real Chrome users, collected in the Chrome User Experience Report and shown in PageSpeed Insights and Search Console. Google's page experience assessment uses field data, so a perfect Lighthouse score does not guarantee passing Core Web Vitals.
The Performance Optimization Checklist
Work through these optimizations in order of typical impact. Each one targets a specific metric, so check your field data first and start with the metric that is failing.
- Keep components on the server by default. Add "use client" only to interactive leaf components such as buttons, forms, and menus. Every client component adds JavaScript the browser must download, parse, and execute. (INP, LCP)
- Prioritize the LCP image. Use
next/imagefor the hero and enable its priority loading option so the browser fetches it early. Never lazy-load the largest above-the-fold image. (LCP) - Size every image correctly. Provide width and height or use
fillwith a sized container, and set an accuratesizesattribute so phones download small variants. (LCP, CLS) - Load fonts with next/font. It self-hosts font files, preloads them, and applies fallback metrics that minimize layout shift when the web font swaps in. (CLS, LCP)
- Defer third-party scripts. Load analytics, chat widgets, and tag managers with
next/scriptusingafterInteractiveorlazyOnloadstrategies, and remove scripts nobody uses. (INP, LCP) - Split heavy client code. Use
next/dynamicfor large components that are not needed immediately, such as charts, editors, maps, and modals. (INP) - Render statically or cache. Pages whose data changes infrequently should be prerendered or cached and revalidated, so visitors receive HTML instantly rather than waiting for database queries. (LCP)
- Stream slow sections. Wrap slow data-dependent components in Suspense boundaries so the rest of the page renders immediately. (LCP)
- Break up long tasks. Move expensive calculations off the critical interaction path, debounce input handlers, and use transitions for non-urgent state updates. (INP)
Re-measure after each change. Optimizations interact, and the fix with the biggest theoretical gain is not always the one that moves your field data.
Which Next.js Feature Fixes Which Metric
Mapping symptoms to tools speeds up diagnosis. Use this table to go from a failing metric to the most likely cause and the Next.js feature that addresses it.
| Metric | Common Cause in Next.js Sites | Primary Fix | How to Verify |
|---|---|---|---|
| LCP | Large, lazy-loaded, or late-discovered hero image | next/image with priority loading and correct sizes | LCP element and timing in the Chrome DevTools Performance panel |
| LCP | Slow server response from uncached dynamic rendering | Static rendering, caching, or streaming with Suspense | Time to First Byte in PageSpeed Insights field data |
| INP | Large client bundles and heavy third-party scripts | Server Components, next/dynamic, and next/script strategies | Long tasks in a Performance recording during interactions |
| CLS | Images, ads, or embeds without reserved space | Explicit dimensions or aspect-ratio containers | Layout shift regions in DevTools rendering tools |
| CLS | Web font swap changing text size | next/font with automatic fallback metrics | Recording page load with network throttling enabled |
When two causes are possible, as with LCP, check Time to First Byte first. If the server responds slowly, no amount of image optimization will fix LCP on its own.
Where Performance Gains Actually Come From
In most Next.js projects, the largest gains come from shipping less JavaScript and serving HTML faster, not from micro-optimizations. This is practitioner analysis from auditing production Next.js sites rather than a formal study, and the specific gains on your site depend on your starting point.
Third-party scripts are the most common hidden cost. Tag managers, session recording tools, chat widgets, and A/B testing scripts often add more main-thread work than the entire application. Audit them quarterly, remove anything without a clear owner, and load the rest with deferred strategies. The INP improvements from removing a single heavy widget can exceed weeks of component-level tuning.
The client boundary is the second lever. Teams migrating from older patterns sometimes mark entire layouts or pages as client components because one child needs state. Moving "use client" down to that child can remove large libraries from the bundle. Run @next/bundle-analyzer to see what each route ships and look for surprises, such as date libraries, icon packs imported wholesale, or markdown parsers that could run on the server.
Content-driven sites gain the most from rendering strategy. When marketing pages or blog posts come from a CMS, they should be prerendered and revalidated on publish rather than rendered on every request. Our roundup of headless CMS platforms that pair with Next.js highlights which tools support webhook-driven revalidation, which makes this pattern straightforward.
Finally, monitor real users continuously. The useReportWebVitals hook lets you send metrics to your analytics, and hosting platforms often provide real-user monitoring dashboards. Regressions usually arrive with a new script or feature, and catching them in days rather than months saves significant search and conversion losses.
Common Mistakes and How to Avoid Them
The most common mistake is optimizing for the Lighthouse score instead of field data. A local test on a fast laptop hides the experience of real users on mid-range phones.
- Lazy-loading the hero image. Lazy loading is the default for next/image, which is right for below-the-fold images but delays LCP when applied to the hero. Mark the LCP image for priority loading.
- Using a background image as the LCP element. CSS background images are discovered late. Render the hero with next/image instead.
- Loading every script in the root layout. Scripts in the root layout run on every page. Load page-specific scripts only on the pages that need them.
- Making the whole page dynamic by accident. Reading cookies or headers high in the tree can force dynamic rendering for an entire route. Isolate request-specific reads in small components.
- Animating layout properties. Animating width, height, or top causes reflow and shifts. Animate transform and opacity instead.
- Injecting banners above content. Cookie notices and promo bars that push content down after load create CLS. Reserve space or overlay them.
- Ignoring hydration cost. Very large server-rendered lists still hydrate on the client if they live inside client components. Paginate or virtualize long lists.
Walkthrough: Fixing a Slow Product Landing Page
Here is a realistic diagnosis and fix sequence for a Next.js landing page whose field data shows poor LCP and INP on mobile.
Step one: read the field data. PageSpeed Insights shows LCP and INP failing for mobile users, while CLS passes. Time to First Byte is acceptable, so server response is not the main problem.
Step two: identify the LCP element. A DevTools Performance recording with mobile throttling reveals that the LCP element is a large hero photograph loaded through a CSS background, discovered only after the stylesheet loads.
Step three: fix LCP. The hero is moved to next/image with priority loading, accurate sizes for mobile and desktop breakpoints, and a modern format served automatically by the image optimizer. The source image is also resized, since serving a huge original wastes bandwidth even after optimization.
Step four: investigate INP. A recording of tapping the main call-to-action button shows long tasks from a chat widget, a session recording script, and a large animation library imported by a client-side layout.
Step five: fix INP. The session recorder is removed after confirming nobody reviews its data. The chat widget moves to lazyOnload. "use client" is pushed from the layout down to the small animated component, and the animation library is replaced with CSS transitions for simple effects.
Step six: verify and monitor. Lab tests confirm improvements immediately, but field data takes time to update because the Chrome User Experience Report aggregates the previous 28 days. The team ships the fixes, tracks metrics with useReportWebVitals in the meantime, and confirms the field data trend in Search Console over the following weeks. A performance budget is added to code review so new scripts require justification.
Key Takeaways
- Google assesses Core Web Vitals from real-user field data at the 75th percentile, not from a single Lighthouse run.
- The good thresholds are LCP at or below 2.5 seconds, INP at or below 200 milliseconds, and CLS at or below 0.1.
- Keeping components on the server and deferring third-party scripts are usually the biggest INP improvements.
- The LCP image should load with priority through next/image, never lazily or as a CSS background.
- Field data reflects a rolling 28-day window, so continuous monitoring catches regressions sooner than waiting for reports.
Frequently Asked Questions
Why is my Next.js site slow even though it uses server rendering?
Server rendering delivers HTML quickly, but pages can still be slow because of large client bundles, unoptimized hero images, heavy third-party scripts, or uncached database queries on every request. Check field data to find the failing metric, then use a DevTools Performance recording to identify whether the bottleneck is the server, assets, or JavaScript.
How do I measure Core Web Vitals for a Next.js app?
Use PageSpeed Insights and Google Search Console for field data from real Chrome users, and Lighthouse or the Chrome DevTools Performance panel for lab diagnosis. Inside the app, the useReportWebVitals hook can send LCP, INP, and CLS measurements to your analytics so you can monitor real users continuously.
Does next/image automatically improve LCP?
next/image helps by serving appropriately sized, modern-format images and reserving space to prevent shifts, but it lazy-loads by default. For the largest above-the-fold image, enable priority loading so the browser fetches it early. Also set an accurate sizes attribute so mobile devices download smaller image variants.
How do I reduce JavaScript bundle size in Next.js?
Keep components as Server Components unless they need interactivity, push the "use client" directive down to small leaf components, lazy-load heavy widgets with next/dynamic, and import only the functions or icons you use. Run the Next.js bundle analyzer to identify large dependencies in each route's client bundle.
What is a good INP score and how do I improve it?
Google considers an INP of 200 milliseconds or less good. Improve it by reducing main-thread work: remove or defer third-party scripts, shrink client bundles, avoid expensive synchronous work inside event handlers, debounce rapid inputs, and use React transitions so urgent updates such as typing stay responsive.
Do Core Web Vitals affect Google rankings?
Core Web Vitals are part of Google's page experience signals, which its ranking systems consider. Google has stated that relevant, helpful content remains the most important factor, so good vitals do not outrank better content. However, faster pages also reduce abandonment and improve conversions, which makes optimization worthwhile regardless of rankings.
Conclusion
The highest-leverage decision is to let field data, not lab scores, choose what you optimize, then attack the failing metric with the matching Next.js feature. For most sites that means fewer client components, fewer third-party scripts, and a prioritized hero image. If you host on your own infrastructure, server response time becomes your responsibility too, so your next step is our Next.js VPS hosting guide covering caching, compression, and reverse proxy setup.




