Core Web Vitals measure real user experience: loading speed (LCP), interactivity (INP), and visual stability (CLS). Poor scores hurt both users and search ranking. Here's how we systematically improve them.
LCP — Largest Contentful Paint (target: under 2.5s)
LCP measures when the largest visible element renders. It's almost always a hero image or heading. The optimisation path is predictable: preload the LCP element with <link rel="preload">. Serve images in WebP/AVIF format. Size images correctly — don't serve a 2000px image in a 400px container. Use priority prop on Next.js Image for the LCP image. Eliminate render-blocking resources that delay the LCP element.
The most common LCP killer we find in audits: a hero section that imports a large JavaScript library before rendering. Move it to the client boundary, render the hero server-side.
INP — Interaction to Next Paint (target: under 200ms)
INP replaced FID as the interactivity metric. It measures the delay between user input and the next paint — across all interactions during the page lifecycle, not just the first. Long JavaScript tasks on the main thread are the primary cause. Fix: break long tasks with scheduler.yield(). Move heavy computation to a Web Worker. Defer non-critical JavaScript. Virtualize long lists.
CLS — Cumulative Layout Shift (target: under 0.1)
Layout shifts happen when elements move after the page loads — usually because images have no size attributes, ads inject content above existing content, or web fonts cause text reflow. Fix: always set explicit width and height on images. Reserve space for dynamic content. Use font-display: optional to prevent FOIT. Test with slow network throttling to catch shifts that happen during load.
The optimisation process
Measure with WebPageTest (real browser, real network) — not just Lighthouse. Identify the worst-performing pages. Profile with Chrome DevTools Performance tab. Fix the biggest bottleneck. Measure again. Repeat. Don't optimise based on assumptions — every fix should be validated with measurement.
Next.js specific wins
Enable the new Next.js Image component for automatic WebP conversion and lazy loading. Use Server Components to eliminate client-side data fetching waterfalls. Use next/font to self-host fonts and eliminate cross-origin font requests. Enable Partial Prerendering (PPR) in Next.js 15 for instant shell rendering.