Introduction
When building modern web applications, speed matters. Users expect fast-loading pages, and search engines reward high-performance websites with better rankings. One of the best ways to speed up your Next.js application is by using server-side caching. Server-side caching stores frequently used data on the server, so the next request can be served instantly without performing heavy processing or slow network calls. In this article, we will learn how caching works in Next.js, why it is important, and how to implement caching using simple examples.
What Is Server-Side Caching?
Server-side caching means storing data on the server so that repeated requests do not fetch data again from an external API or database. Instead, the cached data is returned instantly. This reduces:
Response time
Server load
Cost of API calls
Network usage
Caching is especially useful for applications with data that doesn’t change often, like products, blog posts, public APIs, or settings.
Why Caching Is Important in Next.js Applications
Next.js apps often fetch data at:
Without caching, API calls run every time a page loads. This slows down your server and negatively impacts Lighthouse and Core Web Vitals.
Server-side caching helps you:
Serve pages faster
Reduce calls to external APIs
Improve SEO and user experience
Enhance performance on global deployments
Types of Server-Side Caching in Next.js
Next.js supports different caching strategies:
In-memory caching – simple and fast for small apps
Edge caching – very fast, suitable for global delivery
File-based caching – cache output using revalidation
Third-party caching tools – like Redis or Vercel KV
We will explore each type with examples.
Method 1: In-Memory Caching Using a Simple JavaScript Object
This is the easiest caching method. You store API responses inside a variable in the server.
Example: caching API responses in an API route.
let cache = {};
export default async function handler(req, res) {
const key = "products";
if (cache[key] && Date.now() < cache[key].expiry) {
return res.status(200).json({ data: cache[key].value, cached: true });
}
const response = await fetch("https://fakestoreapi.com/products");
const data = await response.json();
cache[key] = {
value: data,
expiry: Date.now() + 1000 * 60 * 5 // cache for 5 minutes
};
res.status(200).json({ data, cached: false });
}
This approach works for:
Method 2: Using Next.js fetch Cache Options
Next.js provides built-in caching behavior using the fetch() function in server components.
Example
const data = await fetch("https://api.example.com/products", {
next: { revalidate: 60 }
}).then(res => res.json());
This means:
Data is cached on the server
Cache refreshes every 60 seconds
Page loads faster because data comes from cache
This works perfectly for SSR and static pages.
Method 3: Using Route Handlers with Revalidation
In the App Router, you can set caching headers easily.
Example
export const revalidate = 120;
export async function GET() {
const res = await fetch("https://api.example.com/news");
const data = await res.json();
return Response.json(data);
}
Here:
This is ideal for API-level caching.
Method 4: Using Redis for Advanced Server-Side Caching
If your application is large or deployed globally, using Redis provides fast and persistent caching.
Example using Redis in Next.js:
import Redis from "ioredis";
const redis = new Redis(process.env.REDIS_URL);
export default async function handler(req, res) {
const cacheKey = "top-articles";
const cached = await redis.get(cacheKey);
if (cached) {
return res.status(200).json(JSON.parse(cached));
}
const response = await fetch("https://example.com/articles");
const data = await response.json();
await redis.set(cacheKey, JSON.stringify(data), "EX", 300); // cache for 5 minutes
res.status(200).json(data);
}
Benefits of Redis:
Method 5: Using Vercel Edge Caching
Next.js deployed on Vercel automatically enables edge caching for static assets and pages.
You can control caching using HTTP headers:
return new Response(JSON.stringify(data), {
headers: {
"Cache-Control": "s-maxage=300, stale-while-revalidate=600"
}
});
Meaning
This delivers ultra-fast responses globally.
Method 6: Caching Database Queries with Prisma or MongoDB
You can cache results of heavy database queries to reduce load.
Example with in-memory cache:
let dbCache = {};
async function getUsers() {
if (dbCache.users) return dbCache.users;
const users = await prisma.user.findMany();
dbCache.users = users;
return users;
}
This improves server response time significantly.
Method 7: Using SWR for Client-Side + Server-Side Combined Caching
SWR (stale-while-revalidate) works with Next.js to provide both server and client cache.
Example
import useSWR from "swr";
const fetcher = url => fetch(url).then(res => res.json());
export default function Page() {
const { data, error } = useSWR("/api/products", fetcher, {
refreshInterval: 60000
});
return <div>{data ? "Loaded" : "Loading..."}</div>;
}
SWR helps reduce server calls and improves perceived performance.
Best Practices for Server-Side Caching in Next.js
Determine which data should be cached and for how long
Use in-memory caching only for small-scale apps
Use Redis or Vercel KV for large and distributed apps
Set proper cache expiration times
Use Next.js revalidation for simple caching needs
Avoid caching sensitive user-specific data
Regularly monitor cache hit/miss ratios
Following these best practices ensures optimal performance and reliability.
Summary
Server-side caching in Next.js is a powerful way to speed up your application, reduce API usage, and improve overall performance. By using in-memory caching, fetch revalidation, Redis, edge caching, and route handler caching, you can deliver fast and highly optimized responses. Caching helps improve SEO, user experience, and Lighthouse scores, making your Next.js application faster and more efficient for users across the world.