Next.js — Cache Components & Caching Guide
Overview
Cache Components in Next.js is a modern approach to rendering and caching that gives fine-grained control over what is cached, when, and how it’s reused. It leverages Partial Prerendering (PPR) to improve performance and user experience.
Server components that use async functions from Next.js, such as cookies() or headers(), can introduce load time. To handle this efficiently, Next.js allows caching server component results and reusing them across renders.
Rendering Async Server Components with Suspense
When rendering an async server component inside a client component, you must wrap it in <Suspense>. Without Suspense, React will throw an error because async server components are not directly renderable on the client.
// Async Server Component
async function AsyncServerComponent() {
const res = await fetch('https://api.example.com/data');
const data = await res.json();
return <div>{data.title}</div>;
}
// Client Component
import { Suspense } from 'react';
export default function ClientWrapper() {
return (
<Suspense fallback={<div>Loading...</div>}>
<AsyncServerComponent />
</Suspense>
);
}The
fallbackUI can be any React element (spinner, skeleton loader, etc.), providing a seamless user experience.
How to Cache Components
1. Using cache from Next.js
Next.js allows server component caching to reuse component results without re-fetching data on every render.
import { cache } from 'react';
const fetchCachedData = cache(async () => {
const res = await fetch('https://api.example.com/data', { next: { revalidate: 60 } });
return res.json();
});
export default async function MyServerComponent() {
const data = await fetchCachedData();
return <div>{data.title}</div>;
}Where & Why:
- Where: Wrap expensive async functions in
cache(). - Why: Prevents repeated fetching and computation, reducing server load and improving render speed.
2. Caching Fetch Results
Next.js fetch API supports caching via options:
const res = await fetch('https://api.example.com/data', {
next: {
revalidate: 60, // cache for 60 seconds
tags: ['products'], // optional cache tagging
},
});How it works:
cache()caches the server component result.revalidatedefines how long the cache is fresh.tagsallow selective invalidation when a resource changes.
TanStack Query Comparison:
- TanStack Query also caches fetch results on the client.
- Both approaches aim to avoid repeated fetching.
- Next.js caching happens server-side, while TanStack Query works client-side.
Cache Tags Explained
| Tag / Option | Description | When to Use |
|---|---|---|
| cacheTag | Tags that identify cached data. Can be invalidated selectively. | When you want to invalidate specific components or fetches. |
| revalidateTag | Automatically refreshes a cached component when the tag changes. | Use for dynamic data that updates often. |
| updateTag | Manually triggers an update for a cached resource. | When backend data changes and you need immediate UI update. |
| cacheLife | How long the cached data remains valid. | Short-lived: dynamic content; long-lived: static content. |
Use tags and cache lifetimes judiciously to balance freshness and performance.
Links vs Cache Tags
<Link>is used for client-side navigation between pages.- Do NOT rely on Link to trigger cache invalidation. It does not affect server component caches or tags.
- Use
cacheTag,revalidateTag, orupdateTagto control caching behavior explicitly.
How Next.js Fetches Pages
-
Pages in Next.js are prefetched in the background when using
<Link>(client-side navigation). -
When a page fetches data:
- It uses server-side rendering (SSR) or static generation (SSG) depending on your setup.
- Cached components or fetches reduce repeated server calls.
-
Recommended workflow:
- Wrap expensive async server components in
cache(). - Use fetch with
revalidateandtagsoptions. - Use
<Suspense>when rendering async server components in client components. - Use cache tags to selectively invalidate data when necessary.
- Wrap expensive async server components in
References
For the most up-to-date and detailed information, please refer to the official documentation:
- Next.js Docs — Caching Guide
- Next.js Docs — Caching Components
- React Docs — Suspense for Data Fetching
- Next.js Docs — Server Components
- Next.js Fetch API & Caching
- TanStack Query Docs — Caching & Fetching
Summary
- Server components with async operations can block rendering; wrap them in
<Suspense>with a fallback. cache()helps avoid recomputing expensive components.- Fetch caching reduces network requests and improves performance.
- Tags (
cacheTag,revalidateTag,updateTag) allow fine-grained cache control. - Client-side
<Link>navigation does not affect server-side caches. - Combine Suspense + caching + fetch options for optimal page performance.