Understand ISR, revalidatePath, revalidateTag, and caching strategies for optimal performance.
export const revalidate = 3600; // Revalidate every hour
export default async function Page() {
const data = await fetch("https://api.example.com/data");
return <div>{data}</div>;
}// app/api/revalidate/route.ts
import { revalidatePath } from "next/cache";
export async function POST() {
revalidatePath("/blog/[slug]");
revalidatePath("/blog");
return { revalidated: true };
}revalidatePath("/blog/[slug]", "page"); // All dynamic blog posts
revalidatePath("/", "layout"); // Entire site using this layout// app/page.tsx
export default async function Page() {
const res = await fetch("https://api.example.com/posts", {
next: { tags: ["posts"] }
});
const posts = await res.json();
return <div>{posts}</div>;
}// app/api/revalidate/route.ts
import { revalidateTag } from "next/cache";
export async function POST(request) {
const tag = request.nextUrl.searchParams.get("tag");
revalidateTag(tag); // "posts"
return { revalidated: true };
}// Invalidate all blog-related content
revalidateTag("blog");// Cache for 1 hour
const res = await fetch("https://api.example.com/data", {
next: { revalidate: 3600 }
});
// Never cache
const res = await fetch("https://api.example.com/data", {
cache: "no-store"
});
// Cache indefinitely (default)
const res = await fetch("https://api.example.com/data", {
next: { revalidate: false }
});export const revalidate = 86400; // Daily
export async function generateStaticParams() {
const posts = await getPosts();
return posts.map(p => ({ slug: p.slug }));
}
export default async function Post({ params }) {
const post = await getPost(params.slug);
return <article>{post.content}</article>;
}export default async function Dashboard() {
const data = await fetch("https://api.example.com/data", {
next: { tags: ["dashboard"] }
});
return <div>{data}</div>;
}revalidatePath invalidates the cache for a specific URL or route segment, while revalidateTag invalidates all cached entries associated with a given tag across multiple routes. Use revalidateTag when a single content update (like a blog post edit) should purge several pages at once.
Call revalidatePath('/your-route') or revalidateTag('your-tag') inside a Route Handler (app/api/revalidate/route.ts). Protect the endpoint with a secret token by checking a query param or header against an environment variable before revalidating.
Pass { cache: 'no-store' } to fetch to always fetch fresh data, or { next: { revalidate: 0 } } for the same effect. For per-request caching without a time limit use { cache: 'force-cache' }, which is the default for static routes.
Yes — pass the interpolated path like revalidatePath('/posts/123') to purge a single dynamic page, or revalidatePath('/posts/[id]', 'page') to purge all pages matching that segment pattern at once.
generateStaticParams pre-builds specific dynamic routes at build time, while the revalidate option (set via fetch or route config) controls how long those static pages are served before being regenerated in the background. You typically combine both: generateStaticParams to build the initial set and revalidate to keep them fresh after deployment.