The Ultimate Guide to Next.js Caching (Part 1): Browser Cache, CDN, Data Cache & unstable_cache

Search for a command to run...

No comments yet. Be the first to comment.
Meta Description: Learn how to convert your Next.js website into an Android app using Capacitor on Windows. Step-by-step guide with Android Studio setup, APK generation, and deployment. If you've alre

This is Part 2 of my Next.js Caching series. In Part 1, we covered Browser Cache, CDN, Router Cache, Full Route Cache, Data Cache, unstable_cache, and use cache. Previously... We learned that a requ

Introduction If you've been building with React or Next.js, you've probably heard terms like: SSR SSG ISR CSR PPR React Server Components unstable_cache At first, they all sound like differen

While building My Project, one of the biggest challenges wasn't building the UIβit was deciding how to cache data correctly. I wanted my application to: β‘ Feel instant while navigating π Remain SEO

Akash Blog
19 posts
When someone opens your website, does Next.js immediately query your database?
Not always.
A request may pass through multiple cache layers before your database is even touched.
The more requests served from cache, the:
β‘ Faster your app
π° Lower your server costs
π Better your scalability
Think of caching as:
The fastest database query is the one that never runs.
A typical Next.js request looks something like this:
Browser
β
Browser Cache
β
Cloudflare / Vercel CDN
β
Next.js Router Cache
β
Full Route Cache
β
Data Cache
β
unstable_cache / use cache
β
Database
Let's understand what each layer does.
This is the first cache checked.
If your browser already has the file, no network request is made.
Typical cached assets:
Images
CSS
JavaScript
Fonts
Controlled using:
Cache-Control
ETag
Last-Modified
β Best for static assets.
If the browser doesn't have the file, the request reaches the CDN.
User
β
Cloudflare POP
β
Origin Server
If cached:
β No server execution
β No database query
Cloudflare and Vercel both cache assets close to users around the world, reducing latency significantly.
| Cloudflare | Vercel |
|---|---|
| Great for images & static assets | Built into Next.js deployments |
| Works with any hosting | Optimized for App Router |
| Custom cache rules | Automatic Next.js caching |
In my projects, I use:
Cloudflare R2 + CDN β Images
Vercel β Next.js pages & functions
Router Cache exists inside the browser.
Example:
Home
β
Restaurants
β
Restaurant Details
When navigating between pages, Next.js doesn't always fetch everything again.
Instead, it reuses the React Server Component payload, making navigation feel almost instant.
Think of it as navigation cache, not page cache.
This caches the entire rendered page.
Request
β
Cached HTML
β
Response
No React rendering.
No database.
No server execution.
Works with:
Static Pages (SSG)
ISR
Perfect for:
Blogs
Landing pages
Documentation
Marketing websites
Suppose the page itself isn't cached.
Next.js then checks whether the fetched data is cached.
Example:
await fetch(API_URL, {
next: {
revalidate: 60
}
})
The API response is cached for 60 seconds.
Notice:
β The page isn't cached.
β Only the fetched data is.
Best for:
REST APIs
Headless CMS
External APIs
unstable_cacheWhat if you're not using fetch()?
For example:
await prisma.restaurant.findMany()
Next.js can't cache Prisma automatically.
That's where unstable_cache comes in.
import { unstable_cache } from "next/cache";
export const getRestaurants = unstable_cache(
async () => prisma.restaurant.findMany(),
["restaurants"],
{
tags: ["restaurants"],
revalidate: 3600
}
);
Now Prisma isn't executed on every request.
Instead:
Request
β
Cache
β
Database (only when needed)
Perfect for:
Prisma
Drizzle
MongoDB
Redis
Any expensive database query
use cache (The Future)Next.js is gradually replacing unstable_cache with the simpler use cache directive.
Example:
"use cache";
async function getRestaurants() {
return prisma.restaurant.findMany();
}
Same goal.
Cleaner syntax.
If you're starting a new project, keep an eye on use cache as it becomes the preferred API.
| Cache | What It Caches |
|---|---|
| Browser Cache | CSS, JS, Images, Fonts |
| CDN | Static assets & responses |
| Router Cache | Navigation between pages |
| Full Route Cache | Entire rendered page |
| Data Cache | fetch() responses |
unstable_cache |
Database functions & expensive operations |
Imagine someone opens:
https://example.com/restaurants
The request may follow this path:
Browser Cache
β
Miss
β
Cloudflare CDN
β
Miss
β
Full Route Cache
β
Miss
β
Data Cache
β
Miss
β
unstable_cache
β
Hit β
β
Return Restaurant List
Notice something?
The database was never queried.
That's exactly what good caching should achieve.
β Wrapping fetch() inside unstable_cache
β Using no-store everywhere
β Forgetting cache invalidation
β Caching frequently changing data for too long
β Assuming every cache works the same
Each cache has a different responsibility.
Next.js doesn't have one cache.
It has multiple cache layers, each solving a different problem.
A typical production app uses several of them together:
Browser Cache for assets
CDN for global delivery
Router Cache for navigation
Full Route Cache for static pages
Data Cache for fetch()
unstable_cache (or use cache) for database queries
Understanding where each cache fits is the first step toward building fast, scalable applications.
In Part 2, we'll explore:
revalidateTag()
revalidatePath()
updateTag()
SWR
React Query
Dynamic Rendering
Real production caching architecture
Common pitfalls
Happy caching! π
Next.js Caching: https://nextjs.org/docs/app/guides/caching
unstable_cache: https://nextjs.org/docs/app/api-reference/functions/unstable\_cache
React Server Components: https://react.dev/reference/rsc/server-components