⚡ No useEffect Abuse | 🌐 Server-Side Data Fetching | 🖼️ Optimized Images & Fonts | 📦 Less JavaScript, More Static Pages | 🗃️ Proper Caching & Compression
If your Next.js app feels sluggish, you're not alone. Many developers unknowingly slow down their apps with bad practices—especially client-side over-fetching, bloated JavaScript, and poor caching.
When it comes to web performance, every millisecond counts. A slow-loading Next.js app can lead to higher bounce rates, lower SEO rankings, and poor user experience.
Here’s the precise playbook I used to speed up my Next.js app—and how you can do the same.
1️⃣ Server-Side Data Fetching: Stop Overusing useEffect
Many developers are to utilise useEffect to request data on the client side, which slows rendering and requires more JavaScript to be executed by the browser. To speed up data loading and cut down on pointless client-side processing, we instead employed server-side rendering (SSR) and static site generation (SSG).
❌ What to Avoid
🚫 Avoid fetching data inside useEffect unless absolutely necessary.
🚫 Don’t use client-side fetching for static data that rarely changes.
🚫 Perform heavy computations on the client that could be done at build time.
🚫 Client-side data fetching for SEO-critical content (hurts rankings)
Bad Example (Client-side Fetching in useEffect)
// ❌ Avoid this pattern
'use client'
export default function Home( ) {
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/data')
.then(res => res.json())
.then(setData);
}, []);
if (!data) return ;
return (
❌ Avoid this pattern
{data.content}
);
}
✅ What You SHOULD Do (Best Practices)
🌐 Server-Side Data Fetching (Stop Using useEffect for Everything!)
✔ Use getServerSideProps only when necessary (for frequently changing data).
✔ Prefer getStaticProps with revalidation (ISR) for pages that don’t need real-time updates.
✔ Use API routes efficiently to avoid blocking the main thread.
Good Example (Server-side Fetching )
export async function getProductsProps( ) {
const res = await fetch('https://api.example.com/posts');
return {
res.json();
revalidate: 60, // Regenerate every 60 seconds
};
}
export default async function Produts( ) {
const produtData = await getProductsProps( );
return (
Server-Side Data Fetching
{ produtData.content}
);
}
2️⃣ Optimizing Images & Fonts for Faster Rendering
Fonts and images constitute a large portion of the page weight. To lower load times and raise performance ratings, we optimised them.
❌ What to Avoid
🚫 Using
tag directly (misses optimization)
🚫 Avoid using large uncompressed images.
🚫 Don’t use too many custom fonts—stick to one or two optimized fonts.
🚫 Never use external fonts without properly loading them asynchronously.
Bad Example ( img )
export default async function Home( ) {
return (
);
}
✅ What to Do (Best Practices)
✔ Use Next.js Image Component (next/image) to automatically optimize images.
✔ Enable lazy loading to load images only when they enter the viewport.
✔ Use WebP format instead of PNG or JPEG for smaller file sizes.
✔ Self-host custom fonts or use Google Fonts with font-display: swap to prevent render-blockings
Good Example (next/image)
import Image from 'next/image';
import { Inter } from 'next/font/google';
const inter = Inter({ subsets: ['latin'] });
export default function Hero() {
return (
<>
Lightning Fast
>
);
}
3️⃣ Reduce JavaScript: Use More Static Pages
Too much JavaScript increases parsing and execution time, slowing down the page. We reduced JavaScript usage by
❌ What to Avoid
🚫 Avoid shipping unnecessary JavaScript bundles.
🚫 Don’t use client-side navigation for simple static content.
🚫 Slows down rendering, adds unnecessary JavaScript.
Bad Example (client side)
useEffect(( ) => {
fetch("/api/data")
.then(res => res.json())
.then(setData);
}, []);
✅ What to Do
✔ Convert dynamic pages to static pages whenever possible.
✔ Use Incremental Static Regeneration (ISR) to update static pages without full rebuilds.
✔ Use next/link for client-side navigation without full page reloads.
Good Example (Server-side)
export async function getServerSideProps() {
const data = await fetch("https://api.example.com/data").then(res => res.json());
return { props: { data } };
}
Use Static Generation Where Possible (getStaticProps)
Don't dynamically get your data if it doesn't change frequently. Instead, use getStaticProps() to pre-generate pages at build time.🌐
Good Example (Server-side)
export async function getStaticProps() {
const res = await fetch("https://api.example.com/posts");
const posts = await res.json();
return { props: { posts }, revalidate: 60 }; // Refresh every 60s
}
export default function Blog({ posts }) {
return {posts.map((p) => {p.title})};
}
4️⃣ Implement Proper Caching & Compression
Caching and compression drastically improve loading speed by reducing the amount of data transferred over the network.
✅ What to Do:
✔ Use Next.js built-in caching mechanisms.
✔ Enable Gzip or Brotli compression in your hosting environment.
✔ Set proper Cache-Control headers for static assets.
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
compress = true // Enable Gzip compression
images: { // Optimixze extarnal image
remotePatterns: [
{
protocol: "https",
hostname: "**",
},
],
},
};
export default nextConfig;
Caching = less network requests = faster page loads
🚀 The Final Result 📌
Fetch data on the server (getStaticProps/getServerSideProps).
Optimize images & fonts (Next.js handles most optimizations).
Reduce JavaScript (audit, lazy-load, use Edge).
Cache aggressively (static assets should be immutable).
Implement these today for a faster Next.js app! 🚀
🙏 Thank You for Reading ⚡