10 Next.js Performance Tips I Learned from Real Client Projects

1. Introduction: My Wake-Up Call to Web Performance Back when I started working as a freelancer, my main focus was getting features out fast—pages looked beautiful, animations were smooth, and clients were happy. But one day, a client came back saying: "The design is great, but my users are complaining it's slow—especially on mobile." I ran a quick Lighthouse audit, and boom—Performance score: 43. That was my wake-up call. Since then, I’ve optimized several Next.js apps—from portfolio sites to dashboards and job boards. In this blog, I’m sharing 10 practical performance tips that helped me speed up real projects and improve user experience dramatically. And yes—they’re beginner-friendly. 2. Tip #1: Use next/image Instead of Regular Tags The mistake: In one portfolio project, I used standard tags with big PNG files. On desktops, it looked okay. But on mobile networks, it took forever to load. The fix: I switched to Next.js’s built-in next/image component. It automatically: Compresses and optimizes images Supports lazy loading Serves the right image size based on device Example: import Image from 'next/image'; Impact: Page load time improved by 40%, and the Lighthouse "Largest Contentful Paint" (LCP) score jumped from red to green. Beginner Tip: Always use next/image for static images. It handles a LOT of performance work for you. 3. Tip #2: Analyze Your Bundle Size (and Trim the Fat) What happened: In a dashboard project, I imported chart.js, moment, and other big libraries directly. Everything worked—until I checked the production build. The issue: My JavaScript bundle was huge. First load took more than 6 seconds on 3G. Solution: I ran this command to visualize my bundle: npm install @next/bundle-analyzer In next.config.js: const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', }); module.exports = withBundleAnalyzer({}); Then ran: ANALYZE=true npm run build What I saw: Huge chunks coming from moment and unused components. Fixes I made: Replaced moment with date-fns (smaller alternative) Split heavy components using dynamic import Removed unused UI libraries Result: Bundle size dropped from 1.2MB to 600KB. First load time was cut in half. 4. Tip #3: Use SSR Only When You Really Need It What I did wrong: While building a freelance job board using Next.js, I thought using SSR (Server-Side Rendering) for every page was the best idea. Why? Because it sounded "professional" and I wanted live data. The issue: Each page request hit the server and fetched data in real-time. The result? High server load Slower TTFB (Time to First Byte) Laggy experience for users What I learned: SSR is powerful but not always needed. My fix: Used Static Site Generation (SSG) for pages that don’t change often (like homepage, about, etc.) Kept SSR only for job listings with filters/search In some parts, added Incremental Static Regeneration (ISR) to update static pages every few minutes Beginner Tip: Use SSR when content changes on every request (like dashboards or authenticated data). Otherwise, stick to SSG—it’s faster and cheaper. 5. Tip #4: Cache API Results with SWR (Stale-While-Revalidate) The problem: On a personal site, I was fetching my GitHub projects via API on every page load. Looks dynamic, right? But it slowed down the homepage. My fix: I used SWR, a React hook from Vercel that caches data and keeps it fresh in the background. Code example: import useSWR from 'swr'; const fetcher = (url) => fetch(url).then((res) => res.json()); export default function GitHubRepos() { const { data, error } = useSWR('/api/github', fetcher); if (error) return Error loading; if (!data) return Loading...; return {data.length} repositories found; } Benefits:

Apr 6, 2025 - 06:07
 0
10 Next.js Performance Tips I Learned from Real Client Projects

1. Introduction: My Wake-Up Call to Web Performance

Back when I started working as a freelancer, my main focus was getting features out fast—pages looked beautiful, animations were smooth, and clients were happy. But one day, a client came back saying:

"The design is great, but my users are complaining it's slow—especially on mobile."

I ran a quick Lighthouse audit, and boom—Performance score: 43. That was my wake-up call.

Since then, I’ve optimized several Next.js apps—from portfolio sites to dashboards and job boards. In this blog, I’m sharing 10 practical performance tips that helped me speed up real projects and improve user experience dramatically.

And yes—they’re beginner-friendly.

2. Tip #1: Use next/image Instead of Regular Tags

The mistake:

In one portfolio project, I used standard tags with big PNG files. On desktops, it looked okay. But on mobile networks, it took forever to load.

The fix:

I switched to Next.js’s built-in next/image component. It automatically:

  • Compresses and optimizes images
  • Supports lazy loading
  • Serves the right image size based on device

Example:

import Image from 'next/image';

<Image
  src="/profile.jpg"
  width={300}
  height={300}
  alt="My Profile Pic"
/>

Impact:

Page load time improved by 40%, and the Lighthouse "Largest Contentful Paint" (LCP) score jumped from red to green.

Beginner Tip:

Always use next/image for static images. It handles a LOT of performance work for you.

3. Tip #2: Analyze Your Bundle Size (and Trim the Fat)

What happened:

In a dashboard project, I imported chart.js, moment, and other big libraries directly. Everything worked—until I checked the production build.

The issue:

My JavaScript bundle was huge. First load took more than 6 seconds on 3G.

Solution:
I ran this command to visualize my bundle:

npm install @next/bundle-analyzer

In next.config.js:

const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({});

Then ran:

ANALYZE=true npm run build

What I saw:

Huge chunks coming from moment and unused components.

Fixes I made:

  • Replaced moment with date-fns (smaller alternative)
  • Split heavy components using dynamic import
  • Removed unused UI libraries

Result:

Bundle size dropped from 1.2MB to 600KB. First load time was cut in half.

4. Tip #3: Use SSR Only When You Really Need It

What I did wrong:

While building a freelance job board using Next.js, I thought using SSR (Server-Side Rendering) for every page was the best idea.

Why? Because it sounded "professional" and I wanted live data.

The issue:

Each page request hit the server and fetched data in real-time. The result?

  • High server load
  • Slower TTFB (Time to First Byte)
  • Laggy experience for users

What I learned:

SSR is powerful but not always needed.

My fix:

  • Used Static Site Generation (SSG) for pages that don’t change often (like homepage, about, etc.)
  • Kept SSR only for job listings with filters/search
  • In some parts, added Incremental Static Regeneration (ISR) to update static pages every few minutes

Beginner Tip:

Use SSR when content changes on every request (like dashboards or authenticated data).

Otherwise, stick to SSG—it’s faster and cheaper.

5. Tip #4: Cache API Results with SWR (Stale-While-Revalidate)

The problem:

On a personal site, I was fetching my GitHub projects via API on every page load.

Looks dynamic, right? But it slowed down the homepage.

My fix:

I used SWR, a React hook from Vercel that caches data and keeps it fresh in the background.

Code example:

import useSWR from 'swr';

const fetcher = (url) => fetch(url).then((res) => res.json());

export default function GitHubRepos() {
  const { data, error } = useSWR('/api/github', fetcher);

  if (error) return <div>Error loading</div>;
  if (!data) return <div>Loading...</div>;

  return <div>{data.length} repositories found</div>;
}

Benefits: