Back to Blogs
April 30, 2026

How I Optimized Next.js App Router for a 100/100 Lighthouse Score

#Next.js#Performance#Core Web Vitals#React
How I Optimized Next.js App Router for a 100/100 Lighthouse Score

The Business Value of Performance

When architecting modern SaaS platforms, performance isn't just a technical metric—it is a direct driver of revenue. Amazon famously found that every 100ms of latency cost them 1% in sales.

In my recent enterprise builds using the Next.js App Router, I made achieving a 100/100 Google Lighthouse score a non-negotiable architectural baseline. Here is exactly how I eliminate render-blocking resources and optimize Core Web Vitals.

1. Perfecting the Largest Contentful Paint (LCP)

The most common mistake I see in React codebases is lazy-loading the hero image. If an image is "above the fold" (visible immediately when the page loads), it must be prioritized.

Next.js makes this incredibly simple with the priority prop.

(Now, click the Code Block button in your Sanity toolbar and paste this snippet. Set the language to typescript or tsx and the filename to Hero.tsx):

typescript
import Image from 'next/image';

export default function HeroSection() {
  return (
    <div className="relative w-full h-screen">
      <Image 
        src="/enterprise-hero-bg.jpg" 
        alt="SaaS Platform Dashboard"
        fill
        className="object-cover"
        priority={true} // <-- This tells the browser to fetch it immediately
        sizes="100vw"
      />
      <h1 className="relative z-10 text-white">Scale Your Business</h1>
    </div>
  );
}


2. Lazy Loading Heavy Client Components

Server Components in the App Router are incredibly fast, but sometimes you need heavy client-side interactivity (like complex charts or rich text editors). If you import these normally, you bloat your initial JavaScript bundle.

Instead, I use Next.js dynamic imports to completely remove these from the initial load.

(Add another Code Block here. Language: tsx, Filename: Dashboard.tsx):

typescript
'use client';
import dynamic from 'next/dynamic';
import { Suspense } from 'react';

// The chart library won't load until this component is actually rendered
const HeavyAnalyticsChart = dynamic(
  () => import('@/components/charts/AnalyticsChart'),
  { 
    ssr: false, // Disable Server-Side Rendering for this specific component
    loading: () => <div className="h-64 w-full animate-pulse bg-slate-100 rounded-xl" /> 
  }
);

export default function Dashboard() {
  return (
    <section>
      <h2>Revenue Overview</h2>
      <Suspense fallback={<p>Loading analytics framework...</p>}>
        <HeavyAnalyticsChart />
      </Suspense>
    </section>
  );
}

The Result

By rigorously enforcing LCP prioritization, implementing dynamic imports for heavy JS payloads, and utilizing intelligent caching strategies, you can guarantee sub-second load times. This drastically reduces bounce rates and instantly builds trust with your users.


Muhammad Asad

Muhammad Asad

Senior Full-Stack Engineer & Consultant

Share / Connect:

Need help implementing this?

I partner with founders and technical teams to architect scalable, high-performance solutions.