Back to blog
Dashboard with Next.js performance metrics
Performance12 min read

Next.js Performance Optimization - 10 Proven Techniques

A practical guide to optimizing Next.js applications. Learn how to improve Core Web Vitals and speed up your website.

By Bitspire TeamPublished on: November 15, 2025

## TL;DR

Treat performance as a product feature. Optimize rendering, assets, and caching, then measure with Core Web Vitals.

## 10 proven techniques

### 1) Use Server Components by default
Keep data fetching on the server to reduce client JS.

```tsx
export default async function Page() {
  const data = await fetch('https://api.example.com/posts').then(r => r.json());
  return <pre>{JSON.stringify(data, null, 2)}</pre>;
}
```

### 2) Avoid heavy client bundles
- Minimize `use client`
- Split interactive widgets

### 3) Optimize images
- Use `next/image`
- Provide sizes and lazy loading

### 4) Cache aggressively
- Use `fetch` cache
- Revalidate per route

### 5) Reduce third‑party scripts
- Load analytics after interaction
- Remove unused tags

### 6) Stream the UI
- Use Suspense for content chunks

### 7) Use route segment config
- `dynamic`, `revalidate`, `fetchCache`

### 8) Minimize layout shifts
- Reserve media sizes
- Avoid late‑loading fonts

### 9) Use edge/CDN
- Cache static assets globally

### 10) Measure & iterate
- Lighthouse
- WebPageTest

```bash
pnpm dlx lighthouse https://yoursite.com
```

## Checklist

- [ ] LCP < 2.5s
- [ ] CLS < 0.1
- [ ] INP < 200ms

## Final note

Optimizations are cumulative. Ship, measure, adjust — repeat.
  const [posts, setPosts] = useState([]);
  
  useEffect(() => {
    fetch('/api/posts')
      .then(res => res.json())
      .then(setPosts);
  }, []);
  
  return <div>{/* render posts */}</div>;
}
```

### After (Server Component):
```tsx
// app/blog/page.tsx
export default async function BlogPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>{post.title}</article>
      ))}
    </div>
  );
}
```

**Benefits:**
- ✅ Zero JavaScript sent to client
- ✅ Data fetched on server (faster)
- ✅ Better SEO

## 2. Optimize Images with next/image

Next.js has a built-in `Image` component that automatically:
- Generates responsive sizes
- Lazy loads images
- Converts to WebP/AVIF
- Prevents Cumulative Layout Shift (CLS)

```tsx
import Image from 'next/image';

export function Hero() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero image"
      width={1200}
      height={600}
      priority // for above-the-fold images
      placeholder="blur"
      blurDataURL="data:image/jpeg;base64,..."
    />
  );
}
```

**Pro tip:** Use `priority` only for above-the-fold images!

## 3. Implement Static Generation (SSG)

Static pages are **ultra-fast** and cheap to host.

```tsx
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getPosts();
  
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

export default async function BlogPost({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  
  return <article>{/* render post */}</article>;
}
```

**When to use SSG:**
- ✅ Pages that rarely change
- ✅ Blogs, portfolios, landing pages
- ✅ Documentation

## 4. Use Dynamic Imports

Load components only when needed:

```tsx
import dynamic from 'next/dynamic';

const HeavyChart = dynamic(() => import('@/components/HeavyChart'), {
  loading: () => <p>Loading chart...</p>,
  ssr: false, // don't render on server
});

export default function Dashboard() {
  return (
    <div>
      <h1>Dashboard</h1>
      <HeavyChart />
    </div>
  );
}
```

**You save:** Up to 200-300KB of JavaScript bundle!

## 5. Optimize Fonts

Next.js 15 has built-in font optimization:

```tsx
// app/layout.tsx
import { Inter, Poppins } from 'next/font/google';

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
  variable: '--font-inter',
});

const poppins = Poppins({
  subsets: ['latin'],
  weight: ['400', '600', '700'],
  display: 'swap',
  variable: '--font-poppins',
});

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={`${inter.variable} ${poppins.variable}`}>
      <body>{children}</body>
    </html>
  );
}
```

**Benefits:**
- ✅ Self-hosted fonts (privacy!)
- ✅ Zero layout shift
- ✅ Automatic optimization

## 6. Configure Caching Wisely

```tsx
// app/blog/page.tsx
export const revalidate = 3600; // revalidate every hour

export default async function BlogPage() {
  const posts = await fetch('https://api.example.com/posts', {
    next: { revalidate: 3600 }
  }).then(r => r.json());
  
  return <div>{/* posts */}</div>;
}
```

**Strategies:**
- Static data → `revalidate: false`
- Frequently updated → `revalidate: 60`
- Real-time → `revalidate: 0` or Client Component

## 7. Use React Server Actions

Instead of API routes, use Server Actions:

```tsx
// app/contact/page.tsx
async function submitForm(formData: FormData) {
  'use server';
  
  const email = formData.get('email');
  // Process form server-side
  await saveToDatabase(email);
}

export default function ContactPage() {
  return (
    <form action={submitForm}>
      <input name="email" type="email" />
      <button type="submit">Submit</button>
    </form>
  );
}
```

**Advantages:**
- ✅ Less boilerplate
- ✅ Automatic validation
- ✅ Better UX

## 8. Monitoring with Vercel Analytics

```tsx
// app/layout.tsx
import { Analytics } from '@vercel/analytics/react';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        {children}
        <Analytics />
      </body>
    </html>
  );
}
```

Track:
- Core Web Vitals (LCP, FID, CLS)
- Real User Monitoring
- Geographic performance

## 9. Prefetch Links

Next.js automatically prefetches links in viewport:

```tsx
import Link from 'next/link';

export function Navigation() {
  return (
    <nav>
      <Link href="/about" prefetch={true}>
        About
      </Link>
      <Link href="/blog" prefetch={false}>
        Blog {/* don't prefetch */}
      </Link>
    </nav>
  );
}
```

## 10. Bundle Analyzer

Identify what's slowing down your app:

```bash
npm install @next/bundle-analyzer
```

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

module.exports = withBundleAnalyzer({
  // ... config
});
```

Run:
```bash
ANALYZE=true npm run build
```

## Optimization Checklist

Before deployment, make sure:

- [ ] Using Server Components where possible
- [ ] All images through `next/image`
- [ ] Fonts optimized through `next/font`
- [ ] Heavy components lazy-loaded
- [ ] Appropriate revalidate for cached data
- [ ] Lighthouse score > 90
- [ ] Core Web Vitals in green range

## Testing Tools

1. **Lighthouse** - built into Chrome DevTools
2. **PageSpeed Insights** - Google's tool
3. **WebPageTest** - detailed analysis
4. **Vercel Analytics** - real user monitoring

## Real Results

After applying these techniques to our clients' projects:

- 📈 **LCP** improved from 4.2s → **1.1s**
- 📈 **FID** improved from 180ms → **45ms**
- 📈 **Bundle size** reduced by **60%**
- 📈 **Conversion rate** increased by **34%**

## Summary

Next.js optimization is an ongoing process, not a one-time action. Key principles:

1. **Measure first** - don't optimize blindly
2. **Server > Client** - leverage Server Components
3. **Lazy load everything** - load only what's needed
4. **Cache aggressively** - but wisely
5. **Monitor constantly** - track metrics

---

**Need help with optimization?**

At Bitspire, we specialize in building ultra-fast Next.js applications. Contact us to learn how we can improve your site's performance.
#Next.js#Performance#Optimization#Core Web Vitals#SEO
B

Bitspire Team

Author

Article by Bitspire. We build fast, modern websites and web applications.

See our services

Share