Next.js · Lesson 6 of 15
Data Fetching and Caching
Control freshness with cache, revalidate, tags and unstable_cache.
- Intermediate
- 16 min read
- 3 objectives
Before this lessonLesson 5: SEO, Images and Deployment
What you will learn
- Choose static vs dynamic
- Revalidate by time or tag
- Cache a database call
Your Progress
0 of 15 lessons 0%
- Lessons0 / 15
- Completed0
- Est. time left~ 4 hours
Create a free account to keep your progress on every device.
Next.js can cache both HTTP fetch calls and the HTML of a page. Getting this right is the difference between a snappy static site and a dashboard that always shows fresh data.
Three freshness knobs
// Cached until you rebuild (or until a tag is invalidated)
await fetch(url);
// Recheck at most every 60 seconds (ISR-style)
await fetch(url, { next: { revalidate: 60 } });
// Never cache: user-specific or always-changing data
await fetch(url, { cache: "no-store" });Tag and on-demand revalidation
When a mutation happens, you do not want to wait for a timer. Tag the fetch, then invalidate that tag from a server action.
await fetch(url, { next: { tags: ["products"] } });
// in a server action
import { revalidateTag, revalidatePath } from "next/cache";
revalidateTag("products");
revalidatePath("/products");Caching non-fetch work
Database queries are not fetch. Wrap them in unstable_cache (the name is historical; it is the supported helper).
import { unstable_cache } from "next/cache";
export const getPublishedPosts = unstable_cache(
async () => db.post.findMany({ where: { published: true } }),
["published-posts"],
{ revalidate: 60, tags: ["posts"] },
);What makes a page dynamic
Reading cookies(), headers(), or using no-store opts the route into per-request rendering. Keep that at the edge of the tree: a product page can stay static while the cart badge is dynamic.
