Next.js Performance Optimization Guide
3 min read
Next.js Performance Optimization Guide
Discover how to optimize your Next.js applications for better performance, faster load times, and improved user experience.
Image Optimization
Use Next.js Image component effectively:
import Image from 'next/image';
function OptimizedImage() {
return (
<Image
src="/large-image.jpg"
alt="Optimized image"
width={800}
height={600}
placeholder="blur"
blurDataURL="data:image/jpeg;base64,..."
priority={true}
loading="eager"
/>
);
}
Route Optimization
Implement route prefetching:
import Link from 'next/link';
import { useRouter } from 'next/router';
function Navigation() {
const router = useRouter();
// Programmatic prefetching
const prefetchRoute = () => {
router.prefetch('/dashboard');
};
return (
<nav>
{/* Automatic prefetching */}
<Link href="/dashboard" prefetch={true}>
Dashboard
</Link>
<button onMouseEnter={prefetchRoute}>
Go to Dashboard
</button>
</nav>
);
}
Dynamic Imports
Use dynamic imports for code splitting:
import dynamic from 'next/dynamic';
const DynamicComponent = dynamic(() => import('../components/Heavy'), {
loading: () => <p>Loading...</p>,
ssr: false, // Disable server-side rendering if needed
});
function Page() {
return (
<div>
<DynamicComponent />
</div>
);
}
API Route Optimization
Optimize API routes:
// pages/api/data.ts
import { NextApiRequest, NextApiResponse } from 'next';
import nc from 'next-connect';
import cors from 'cors';
import rateLimit from 'express-rate-limit';
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // limit each IP to 100 requests per windowMs
});
const handler = nc<NextApiRequest, NextApiResponse>()
.use(cors())
.use(limiter)
.get(async (req, res) => {
const data = await fetchDataWithCaching();
res.json(data);
});
export default handler;
Caching Strategies
Implement effective caching:
// lib/cache.ts
import LRU from 'lru-cache';
const cache = new LRU({
max: 500,
maxAge: 1000 * 60 * 60 // 1 hour
});
export async function fetchWithCache(key: string, fetchFn: () => Promise<any>) {
const cached = cache.get(key);
if (cached) return cached;
const fresh = await fetchFn();
cache.set(key, fresh);
return fresh;
}
// Usage in getStaticProps
export async function getStaticProps() {
const data = await fetchWithCache('key', () =>
fetch('https://api.example.com/data')
);
return {
props: { data },
revalidate: 60 // ISR - revalidate every minute
};
}
Bundle Optimization
Analyze and optimize your bundle:
// next.config.js
module.exports = {
webpack: (config, { dev, isServer }) => {
// Enable tree shaking
config.optimization.usedExports = true;
// Add bundle analyzer in build
if (!dev && !isServer) {
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
config.plugins.push(
new BundleAnalyzerPlugin({
analyzerMode: 'static',
reportFilename: './bundles/report.html'
})
);
}
return config;
}
};
Best Practices
- Use Static Generation when possible
- Implement proper caching strategies
- Optimize images and fonts
- Use proper code splitting
- Implement proper error boundaries
- Monitor performance metrics
- Use proper lazy loading
Conclusion
Performance optimization in Next.js requires a multi-faceted approach. Start with the basics and gradually implement more advanced optimizations as your application grows.