How to Improve Core Web Vitals in Next.js: A Complete Guide
OverMCP Team
How to Improve Core Web Vitals in Next.js: A Complete Guide
TL;DR: To improve Core Web Vitals in Next.js, focus on optimizing images (use next/image), reduce JavaScript execution time (use dynamic imports and lazy loading), and prevent layout shifts (reserve space for images and ads). This guide walks through each metric with concrete code examples.
Core Web Vitals are a set of metrics that Google uses to measure user experience. They include Largest Contentful Paint (LCP), First Input Delay (FID), and Cumulative Layout Shift (CLS). For Next.js apps, these metrics are crucial for SEO and user retention. Below, I'll show you exactly how to improve each one.
1. Optimize Largest Contentful Paint (LCP)
The LCP element is typically a hero image, video poster, or large text block. Here's how to optimize it in Next.js.
Use the `next/image` Component
Next.js provides the Image component that automatically optimizes images. It serves responsive images in modern formats like WebP, lazy-loads offscreen images, and resizes them on the fly.
import Image from 'next/image';
export default function Hero() {
return (
<div style={{ position: 'relative', width: '100%', height: '500px' }}>
<Image
src="/hero.jpg"
alt="Hero image"
fill
priority
sizes="(max-width: 768px) 100vw, 50vw"
/>
</div>
);
}Key points:
priority for above-the-fold images to skip lazy loading.sizes to help the browser pick the right image size.fill with a parent container that has position: relative.Preload Critical Resources
Use the next/head component to preload fonts, images, or scripts that are critical for LCP.
import Head from 'next/head';
export default function Layout({ children }) {
return (
<>
<Head>
<link rel="preload" href="/fonts/Inter.woff2" as="font" type="font/woff2" crossOrigin="anonymous" />
</Head>
{children}
</>
);
}Minimize Render-Blocking Resources
Reduce the impact of CSS and JavaScript that blocks rendering. Next.js automatically inlines critical CSS for the initial page load (since version 12), but you can further optimize:
next/script with strategy="afterInteractive" for non-critical scripts.2. Improve First Input Delay (FID) / Interaction to Next Paint (INP)
FID measures the time from when a user first interacts with your app to when the browser can respond. INP is a more comprehensive metric coming in 2024. The goal is to keep the main thread free.
Reduce JavaScript Execution Time
import dynamic from 'next/dynamic';
const HeavyComponent = dynamic(() => import('../components/HeavyComponent'), {
loading: () => <p>Loading...</p>,
});dynamic with ssr: false for client-only components.Optimize Third-Party Scripts
Use next/script with the appropriate strategy:
import Script from 'next/script';
export default function Page() {
return (
<>
<Script
src="https://analytics.example.com/script.js"
strategy="lazyOnload"
/>
<Script
src="https://widget.example.com/widget.js"
strategy="afterInteractive"
/>
</>
);
}beforeInteractive: For critical scripts (e.g., polyfills).afterInteractive: For scripts that can wait until the page is interactive.lazyOnload: For non-essential scripts (e.g., analytics).Avoid Long Tasks
Break up long tasks using setTimeout or requestIdleCallback. Use tools like the Performance panel in Chrome DevTools to identify long tasks.
3. Minimize Cumulative Layout Shift (CLS)
CLS measures visual stability. It occurs when elements shift after the user has started interacting.
Reserve Space for Images
When using next/image, always set width and height or use fill with a container that has a defined aspect ratio.
<div style={{ position: 'relative', width: '100%', paddingTop: '56.25%' }}>
<Image src="/video-thumbnail.jpg" alt="Video" fill />
</div>This ensures the browser reserves the correct space before the image loads.
Reserve Space for Ads and Embeds
If you use ads or embeds, wrap them in a container with a fixed size or aspect ratio.
<div style={{ width: '300px', height: '250px', background: '#f0f0f0' }}>
{/* Ad code */}
</div>Avoid Inserting Content Above Existing Content
Dynamic inserts (e.g., banners, cookie notices) should not push down existing content. Use position: fixed or position: sticky to overlay them without affecting layout.
Use `next/font` for Font Optimization
Font loading can cause layout shifts. Next.js 13+ includes next/font that automatically optimizes fonts and eliminates layout shift.
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function Layout({ children }) {
return <div className={inter.className}>{children}</div>;
}4. General Performance Tips
Enable Incremental Static Regeneration (ISR)
For content that changes infrequently, use ISR to serve static pages with periodic revalidation.
export async function getStaticProps() {
const data = await fetch('https://api.example.com/posts');
const posts = await data.json();
return {
props: { posts },
revalidate: 60, // seconds
};
}Use CDN and Caching
Next.js automatically serves static assets from a CDN when deployed on Vercel or Netlify. Ensure caching headers are set for images and static files.
Monitor with Real User Monitoring (RUM)
Use tools like web-vitals library in Next.js to track Core Web Vitals in production.
import { useEffect } from 'react';
import { getCLS, getFID, getLCP } from 'web-vitals';
export default function App({ Component, pageProps }) {
useEffect(() => {
getCLS(console.log);
getFID(console.log);
getLCP(console.log);
}, []);
return <Component {...pageProps} />;
}5. Tools to Measure Core Web Vitals
6. Common Pitfalls in Next.js
_app.js blocks rendering. Use CSS modules or Tailwind's purge.next/script with appropriate strategies.FAQ
How do I check Core Web Vitals in Next.js?
You can use the web-vitals library in your app to log metrics, or use Google's PageSpeed Insights and Chrome DevTools Lighthouse tab to analyze your site.
What is the most important Core Web Vital for SEO?
Google considers all three metrics (LCP, FID, CLS) equally, but LCP is often the hardest to optimize. A poor LCP can significantly affect user experience and rankings.
Can I ignore Core Web Vitals if my site loads fast?
No. Fast load times don't guarantee good Core Web Vitals. For example, a fast-loading page can still have CLS issues from late-loading images. Always measure and optimize for each metric.