DEV Community

Cover image for Optimizing Next.js Performance: Achieving Perfect Lighthouse Scores
Jananadi W
Jananadi W

Posted on

Optimizing Next.js Performance: Achieving Perfect Lighthouse Scores

In today's digital landscape, website performance is crucial for user experience and search engine rankings. A fast, responsive site not only keeps visitors engaged but also improves conversion rates and overall satisfaction. One of the most reliable and accessible tools for measuring web performance is 'Lighthouse', an open-source, automated web tool developed by Google. Lighthouse analyses web apps, providing scores on Performance, Accessibility, Best Practises, and SEO.

Recently I was on a mission to optimize my Next.js website (github repo), aiming for perfect Lighthouse score. Here's how I achieved this feat and the lessons I learned along the way.

1. Image Optimization

I used Next.js's built-in Image component. It's automatically handling lazy loading, resizing, and serving images in modern formats like WebP when supported by the browser.

<Image
  width={100}
  height={113}
  alt="thumbnail"
  loading="lazy"
  src={`/images/${article.image}`}
  className="rounded transition border-gray-500 group-hover:border-gray-500 sm:order-1 sm:col-span-2 sm:translate-y-1"
/>
Enter fullscreen mode Exit fullscreen mode

2. Code Minification

Next.js automatically minifies JavaScript in production builds. I ensured this feature was enabled in my next.config.js:

module.exports = {
  reactStrictMode: true,
  swcMinify: true,
};
Enter fullscreen mode Exit fullscreen mode

3. Caching Implementation

Next.js provides efficient caching strategies out of the box. By relying on these default behaviors, I ensured that my site was making the most of browser and server-side caching without any additional configuration.

4. Reducing Server Response Time: Static Generation FTW

I utilized Next.js's static generation capabilities for most of my content. This approach pre-renders pages at build time, significantly reducing server response time:

useEffect(() => {
  fetch("/api/data")
    .then((response) => response.json())
    .then((fetchedData: Data) => setData(fetchedData));
}, []);
Enter fullscreen mode Exit fullscreen mode

5. Eliminating Render-Blocking Resources

Next.js automatically handles code splitting and lazy loading of JavaScript modules. I took advantage of this by using dynamic imports for components that weren't immediately necessary:

import dynamic from 'next/dynamic'
import Loading from './Loading'

const DynamicComponent = dynamic(() => import('./HeavyComponent'), {
  loading: () => <Loading />,
})
Enter fullscreen mode Exit fullscreen mode

6. Lazy Loading on Skeleton loaders

While the Image component handled lazy loading for images, I implemented lazy loading for other content as well. I created a reusable Loading component to display while content was being fetched:

const Loading = memo(() => {
  return (
    <div className="space-y-3 animate-pulse mt-24 mb-12">
      {/* Loading skeleton */}
    </div>
  );
});
Enter fullscreen mode Exit fullscreen mode

7. CDN Usage: Vercel's Global Network

By deploying my Next.js app on Vercel, I automatically benefited from their global CDN, ensuring fast content delivery regardless of the user's location.

8. Mobile Optimization

I used Tailwind CSS for its responsive design utilities, ensuring my site looked great on all devices:

<div className="mx-auto min-h-screen max-w-screen-xl px-6 py-12 font-sans md:px-12 md:py-20 lg:px-24 lg:py-0 text-white">
  <div className="lg:flex lg:justify-between lg:gap-4">
    {/* Content */}
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Additional Optimizations

  • I used modern React patterns like hooks and functional components for better performance and readability.
  • Implemented performance monitoring tools like Vercel Analytics and Speed Insights.
        <Analytics />
        <SpeedInsights />
Enter fullscreen mode Exit fullscreen mode
  • Utilized Next.js's file-based routing system for efficient navigation.
  • Adopted TypeScript for improved code quality and fewer runtime errors.

After all, it was a rewarding process to see all 100 on the scoreboard on Lighthouse. Have you optimized your Next.js project? What strategies worked best for you? Share your experiences in the comments below!

Top comments (0)