Achieving Perfect 100/100 Core Web Vitals in Next.js 15
Step-by-step performance engineering guide: LCP image priority, INP optimization, font preloading, dynamic imports, and streaming SSR.
Search engine rankings and user retention depend heavily on web performance. Google's Core Web Vitals (LCP, INP, CLS) measure real-world user experience.
Here is the exact playbook I used to achieve 100/100 Lighthouse Performance on lanadev.web.id.
The Three Core Metrics
| Metric | Target | Focus Area |
|---|---|---|
| **LCP** (Largest Contentful Paint) | < 1.2s | Hero image delivery, SSR streaming |
| **INP** (Interaction to Next Paint) | < 100ms | Non-blocking main thread, debouncing |
| **CLS** (Cumulative Layout Shift) | 0.00 | Strict aspect ratios, font display swap |1. Eliminating Largest Contentful Paint (LCP) Delays
Hero images are the most common cause of poor LCP scores. Always preload and prioritize hero imagery:
import Image from "next/image";
export function HeroImage() {
return (
<Image
src="/image-me.webp"
alt="Muhammad Maulana Firdaussyah"
width={600}
height={800}
priority
fetchPriority="high"
quality={85}
sizes="(max-width: 768px) 100vw, 50vw"
className="object-cover object-top"
/>
);
}2. Font Optimization with next/font
Loading external Google Fonts via <link> causes render-blocking roundtrips. Next.js font optimization downloads font binaries at build time and inlines CSS:
import { Geist, Geist_Mono } from "next/font/google";
export const geistSans = Geist({
variable: "--font-geist-sans",
subsets: ["latin"],
display: "swap",
preload: true,
});3. Code Splitting & Lazy Component Mounting
Non-critical sections below the fold should not delay initial JavaScript execution:
import dynamic from "next/dynamic";
const TestimonialsSection = dynamic(
() => import("@/components/home/TestimonialSection").then(m => m.TestimonialSection),
{ ssr: true, loading: () => <div className="h-96 animate-pulse bg-muted" /> }
);Applying these techniques guarantees blazing fast page loads across all global edge locations.