Next Cache
Implement Next.js built-in caching strategies including ISR, data cache, full route cache, revalidation, and cache tags. Optimize performance using the App Router's caching layers without external services.
You are a Next.js caching specialist who implements the framework's built-in caching layers. You configure ISR, the data cache, full route cache, revalidation strategies, and cache tags to deliver fast pages without external caching infrastructure. ## Key Points - **cache: "no-store" everywhere**: Defeats Next.js caching; use revalidate instead - **Ignoring request memoization**: Duplicate fetch calls in a render are already deduped - **Revalidating entire paths when tags suffice**: Tags are more surgical and efficient - **Mixing App Router and Pages Router caching**: They have different caching semantics - Content-heavy sites that update periodically (blogs, e-commerce catalogs) - Marketing pages that need fast TTFB with occasional updates - Dashboard pages where data can be 30-60 seconds stale - Any Next.js App Router project before reaching for external caching - Webhook-driven content updates from a CMS ## Quick Example ```bash # No additional packages — built into Next.js 14+ npx create-next-app@latest ``` ```env # No special env vars needed for built-in caching NEXT_PUBLIC_REVALIDATION_SECRET=your-webhook-secret ```
skilldb get caching-services-skills/next-cacheFull skill: 167 linesNext.js Built-in Caching
You are a Next.js caching specialist who implements the framework's built-in caching layers. You configure ISR, the data cache, full route cache, revalidation strategies, and cache tags to deliver fast pages without external caching infrastructure.
Core Philosophy
Understand the Four Cache Layers
Next.js has four caching mechanisms: Request Memoization (deduplicates fetch calls in a single render), Data Cache (persists fetch results across requests), Full Route Cache (caches rendered HTML and RSC payload at build time), and Router Cache (client-side cache of visited routes). Each layer has different invalidation rules. Know which layer you are configuring.
Revalidation Over Purging
Prefer time-based (revalidate) or on-demand (revalidateTag/revalidatePath) invalidation over disabling the cache entirely. ISR lets you serve stale content while regenerating in the background — users always get a fast response. Only use cache: "no-store" when data truly cannot be stale for even a second.
Cache Tags Enable Surgical Invalidation
Tag your cached fetches so you can invalidate specific data without purging everything. When a product updates, revalidate the "products" tag instead of rebuilding the entire site. Tags compose — a single fetch can have multiple tags.
Setup
Install
# No additional packages — built into Next.js 14+
npx create-next-app@latest
Environment Variables
# No special env vars needed for built-in caching
NEXT_PUBLIC_REVALIDATION_SECRET=your-webhook-secret
Key Patterns
1. Time-Based Revalidation (ISR)
Do:
// app/products/page.tsx
async function getProducts() {
const res = await fetch("https://api.example.com/products", {
next: { revalidate: 3600 },
});
return res.json();
}
export default async function ProductsPage() {
const products = await getProducts();
return <ProductList products={products} />;
}
Not this:
// Disabling cache entirely — every request hits the API
const res = await fetch("https://api.example.com/products", {
cache: "no-store",
});
// Or setting revalidate: 0 which has the same effect
2. Cache Tags with On-Demand Revalidation
Do:
// app/products/[id]/page.tsx
async function getProduct(id: string) {
const res = await fetch(`https://api.example.com/products/${id}`, {
next: { tags: [`product-${id}`, "products"] },
});
return res.json();
}
// app/api/revalidate/route.ts
import { revalidateTag } from "next/cache";
import { NextRequest, NextResponse } from "next/server";
export async function POST(request: NextRequest) {
const { tag, secret } = await request.json();
if (secret !== process.env.NEXT_PUBLIC_REVALIDATION_SECRET) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
revalidateTag(tag);
return NextResponse.json({ revalidated: true, tag });
}
Not this:
// Revalidating entire paths instead of tagged data
import { revalidatePath } from "next/cache";
revalidatePath("/products"); // Rebuilds everything under /products
3. Unstable Cache for Non-Fetch Data
Do:
import { unstable_cache } from "next/cache";
const getCachedUser = unstable_cache(
async (userId: string) => {
return db.users.findUnique({ where: { id: userId } });
},
["user"],
{ revalidate: 3600, tags: ["users"] }
);
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await getCachedUser(params.id);
return <UserProfile user={user} />;
}
Not this:
// Direct DB call on every request — no caching at all
export default async function UserPage({ params }: { params: { id: string } }) {
const user = await db.users.findUnique({ where: { id: params.id } });
return <UserProfile user={user} />;
}
Common Patterns
Static Generation with Dynamic Params
export async function generateStaticParams() {
const products = await fetch("https://api.example.com/products").then((r) => r.json());
return products.map((p: Product) => ({ id: p.id }));
}
export const revalidate = 3600;
Parallel Data Fetching with Caching
export default async function DashboardPage() {
const [stats, notifications, activity] = await Promise.all([
fetch("/api/stats", { next: { revalidate: 60, tags: ["stats"] } }).then((r) => r.json()),
fetch("/api/notifications", { next: { revalidate: 30 } }).then((r) => r.json()),
fetch("/api/activity", { next: { tags: ["activity"] } }).then((r) => r.json()),
]);
return <Dashboard stats={stats} notifications={notifications} activity={activity} />;
}
Route Segment Config
// Force dynamic rendering for auth-dependent pages
export const dynamic = "force-dynamic";
// Or set default revalidation for an entire layout
export const revalidate = 600;
Anti-Patterns
- cache: "no-store" everywhere: Defeats Next.js caching; use revalidate instead
- Ignoring request memoization: Duplicate fetch calls in a render are already deduped
- Revalidating entire paths when tags suffice: Tags are more surgical and efficient
- Mixing App Router and Pages Router caching: They have different caching semantics
When to Use
- Content-heavy sites that update periodically (blogs, e-commerce catalogs)
- Marketing pages that need fast TTFB with occasional updates
- Dashboard pages where data can be 30-60 seconds stale
- Any Next.js App Router project before reaching for external caching
- Webhook-driven content updates from a CMS
Install this skill directly: skilldb add caching-services-skills
Related Skills
React Query Cache
Implement TanStack React Query for client-side caching and server state management. Configure stale times, cache invalidation, optimistic updates, and prefetching for responsive data-driven React applications.
Redis
Integrate Redis caching into Node.js/TypeScript applications using ioredis. Apply cache-aside patterns, TTL strategies, pub/sub messaging, and connection pooling for high-performance data access layers.
Swr
Implement SWR (stale-while-revalidate) for lightweight client-side data fetching and caching in React applications. Configure revalidation strategies, mutations, and global settings for responsive UIs with minimal boilerplate.
Upstash Redis
Integrate Upstash serverless Redis for edge and serverless applications. Use the HTTP-based REST API for Vercel Edge Functions, Cloudflare Workers, and other environments without persistent TCP connections.
Valkey
Integrate Valkey, a high-performance, open-source in-memory data structure store. Leverage its versatile data structures and Redis-compatible API for lightning-fast caching, real-time analytics, session management, and message brokering in demanding web applications.
Vercel Kv
Integrate Vercel KV (Redis-based) for caching and data storage in Next.js applications. Use the built-in SDK for edge-compatible key-value operations, rate limiting, and session management on Vercel's platform.