How I Upgraded My Portfolio to a 90+ Lighthouse Score
Published on August 6, 2025
The Starting Point: A Good Site with a Bad Score
After successfully migrating my portfolio to Next.js and deploying it on Vercel, everything looked great. The animations were smooth, the content was structured, and the design was clean. However, when I ran a Google Lighthouse audit, the results were humbling: a performance score of just 49.
The report flagged two major issues:
- Largest Contentful Paint (LCP): A shocking 6.2 seconds.
- Cumulative Layout Shift (CLS): A high 0.285.
My site looked fast, but the data told a different story. It was clear that the user experience, especially on slower connections, was poor. I knew I had to fix it.
Diagnosing the Problem: The Render-Blocking Culprit
The root cause was a workaround I had implemented earlier. During the initial setup, I faced some stubborn build errors with Tailwind CSS. To get the site deployed, I opted to use the Tailwind CDN script directly in my <head>
:
<script src="[https://cdn.tailwindcss.com](https://cdn.tailwindcss.com)"></script>
While this worked, it was a performance disaster. This single script was a render-blocking resource. The browser had to download and execute this large CSS file before it could finish painting the main content of the page, leading to the terrible LCP. The CLS was happening because the page would first render as unstyled HTML, and then all the elements would shift into place once the CSS finally loaded.
The Solution: A Three-Step Performance Overhaul
To fix this, I went back to the fundamentals and implemented the modern, built-in best practices for Next.js.
1. Stabilizing the Foundation
The original build errors stemmed from using a bleeding-edge version of Next.js. The first step was to downgrade from 15.x
to the latest stable version, 14.2.3
. This resolved the underlying build instability and allowed me to use the standard toolchain.
2. Adopting the Built-in CSS Process
With a stable foundation, I could finally remove the slow CDN script. I re-implemented the standard Next.js method for handling CSS:
- I updated my
tailwind.config.mjs
andpostcss.config.mjs
files. - I added the standard
@tailwind
directives back into myglobals.css
file.
This allowed Next.js's build process to do its magic. It now analyzes my code, finds only the Tailwind classes I'm actually using, and creates a tiny, highly-optimized CSS file that is bundled with the rest of my site's assets. This completely eliminated the render-blocking issue.
3. Self-Hosting the Font
The final optimization was to remove the last external network request. Instead of using next/font/google
, I downloaded the "Inter" font files and used next/font/local
. This means the font is now served directly from my own project files, making it faster and more reliable.
The Result: A World-Class Performance Score
After deploying these changes, I ran the Lighthouse audit again. The results were night and day:
- Performance Score: Jumped from 49 to 75+ (and well into the 90s on desktop).
- Cumulative Layout Shift (CLS): Dropped to a perfect 0.
This journey was a powerful lesson in the importance of adhering to best practices. A good-looking site is one thing, but a high-performance site that provides an excellent user experience is what truly defines a professional, top-tier project.