Back to Blog
Development14 min read

Next.js Performance Optimization: Achieve Perfect Lighthouse Scores

Core Web Vitals, image optimization, caching strategies, server components, and bundle splitting — everything you need to get a 100/100 Lighthouse score on your Next.js app.

Growthency

Growthency Team

March 5, 2025

Why Next.js Performance Matters More Than Ever

Google's Core Web Vitals are now a direct ranking factor. Sites that load slowly lose search visibility, conversion rates, and revenue. The good news: Next.js is built for performance, and with the right configuration, hitting a 100/100 Lighthouse score is achievable for most apps.


Understanding Core Web Vitals

The three Core Web Vitals:

  • LCP (Largest Contentful Paint): Time until the largest content element loads. Target: under 2.5 seconds
  • INP (Interaction to Next Paint): Responsiveness to user interactions. Target: under 200ms
  • CLS (Cumulative Layout Shift): Visual stability during load. Target: under 0.1

Measure your current scores in Chrome DevTools Lighthouse tab before making any changes. You need a baseline.


1. Optimize Images With next/image

Images are the #1 cause of poor LCP scores. The next/image component solves most image performance issues automatically.

`tsx

import Image from 'next/image'

src="/hero.webp"

alt="Hero image description"

width={1200}

height={630}

priority

quality={85}

sizes="(max-width: 768px) 100vw, 1200px"

/>

`

Critical image checklist:

  • Use priority prop on your LCP image (usually hero image)
  • Always specify sizes to prevent serving oversized images on mobile
  • Serve WebP format (next/image does this automatically)
  • Never use raw img tags for content images
Next.js Lighthouse score showing 100/100 performance rating

2. Server Components vs Client Components

The single biggest performance improvement in Next.js App Router is using Server Components correctly.

Rule of thumb: Use Server Components by default. Only add "use client" when you need React state, effects, browser APIs, or event listeners.

Moving data-fetching to Server Components eliminates client-side loading states, reduces JavaScript bundle size, and improves SEO — all at once.


3. Route-Level Code Splitting and Lazy Loading

Next.js automatically code-splits at the route level. Go further with component-level lazy loading.

`tsx

import dynamic from 'next/dynamic'

const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {

loading: () =>

,

ssr: false

})

`

When to lazy load:

  • Components only visible below the fold
  • Components that are conditionally shown (modals, drawers)
  • Heavy third-party integrations (charts, maps, rich text editors)

4. Caching Strategy

`tsx

// Static page

export const dynamic = 'force-static'

// ISR — revalidate every 60 seconds

export const revalidate = 60

// Cached fetch

async function getData() {

const res = await fetch('https://api.example.com/data', {

next: { revalidate: 3600 }

})

return res.json()

}

`

Cache strategy by page type:

  • Marketing pages: static generation
  • Blog posts: ISR with 1-hour revalidation
  • Product pages: ISR with 5-minute revalidation
  • User dashboards: dynamic (no cache)

5. Bundle Size Optimization

`bash

ANALYZE=true npm run build

`

Common bundle size wins:

  • Replace moment.js with date-fns (from 300KB to 20KB)
  • Use lodash-es and tree-shake specific functions
  • Replace full icon libraries with individual icon imports

6. Font Optimization

`tsx

import { Inter, Syne } from 'next/font/google'

const inter = Inter({

subsets: ['latin'],

display: 'swap',

variable: '--font-inter'

})

`

next/font automatically self-hosts fonts, adds size-adjust to prevent CLS, and uses font-display swap.


The Performance Optimization Checklist

| Category | Optimization | Impact |

|----------|-------------|--------|

| Images | next/image with priority on LCP | High |

| Components | Server Components by default | High |

| Caching | ISR for content pages | High |

| Fonts | next/font/google | Medium |

| Code splitting | Dynamic imports for heavy components | Medium |

| Bundle | Remove unused dependencies | Medium |

Run Lighthouse after each optimization. Most Next.js apps can reach 90+ Performance after implementing the first three items on this list.

#nextjs#performance#lighthouse#core web vitals#react

Share this article

Growthency

Growthency Team

The Growthency team helps businesses launch, scale, and grow using modern software, AI tools, and proven digital strategy. We've worked with 200+ startups and growing businesses worldwide.

About Growthency