HomeBlogFrontend
Frontend

Web Performance: Core Web Vitals in 2025

A practical guide to achieving green Core Web Vitals scores — LCP, INP, and CLS — with real techniques that work on production Next.js and React applications.

Oct 14, 2024 8 min read 26.3k views
Performance Web Vitals Next.js SEO

Core Web Vitals are no longer just a SEO checkbox — they directly impact conversion rates. A 100ms improvement in LCP correlates with a 1-3% uplift in conversion across most e-commerce sites. Here's the practical playbook I use to green all three metrics on production apps.

LCP: Largest Contentful Paint

LCP measures when the largest visible element renders. It's almost always a hero image or heading. The two biggest wins: preload your LCP image with a <link rel=preload> in the document head, and ensure your LCP element is in the server-rendered HTML — not injected by JavaScript.

tsx
// In Next.js — priority prop generates a <link rel=preload>
<Image
  src="/hero.jpg"
  alt="Hero"
  width={1200}
  height={600}
  priority  // ← critical for LCP images
  sizes="100vw"
/>
💡 Tip

Use Chrome DevTools' Performance panel to identify your LCP element. It's often not the image you think it is — sometimes it's a large block of text or a background image loaded via CSS.

INP: Interaction to Next Paint (replaced FID)

INP measures the latency of all interactions on the page, not just the first. Long tasks — JavaScript that runs for more than 50ms — are the primary cause of poor INP. Use the scheduler.yield() API to break long tasks into smaller chunks that yield back to the browser between frames.

javascript
async function processLargeList(items) {
  for (let i = 0; i < items.length; i++) {
    processItem(items[i]);
    // Yield every 50 items to keep the main thread responsive
    if (i % 50 === 0) {
      await scheduler.yield();
    }
  }
}

CLS: Cumulative Layout Shift

CLS is caused by elements that shift after initial render — typically images without dimensions, ads, and dynamically injected banners. The fix is almost always the same: reserve space for dynamic content before it loads. For images, always specify width and height. For ads and embeds, use a min-height placeholder.

Found this useful?

Share it with your network