Skip to content
nextjs-caching logo

Next.js Caching

nextjs-caching

Complete Next.js caching system with 'use cache' directive (Next.js 16). PROACTIVELY activate for: (1) Understanding 4 caching layers (Request Memoization, Data Cache, Full Route Cache, Router Cache), (2) Cache Components with 'use cache' directive, (3) fetch() caching options, (4) cacheLife() an...

SKILL.md

Full skill instructions

Quick Reference

Cache LayerLocationDurationPurpose
Request MemoizationServerPer-requestDedupe same fetches
Data CacheServerPersistentStore fetch results
Full Route CacheServerPersistentPre-rendered HTML/​RSC
Router CacheClientSessionClient-side navigation

Next.js 16: 'use cache' Directive

DirectiveScopeUse Case
'use cache'Default cacheGeneral caching
'use cache: remote'CDN/​Edge cacheStatic shared content
'use cache: private'Per-user cacheUser-specific data
Cache FunctionCodePurpose
cacheLife('hours')DurationSet cache lifetime
cacheTag('posts')TaggingEnable targeted revalidation

Fetch Options

Fetch OptionCodeEffect
Defaultfetch(url)Cached indefinitely
No cache{ cache: 'no-store' }Always fresh
Revalidate{ next: { revalidate: 60 } }Stale after 60s
Tags{ next: { tags: ['posts'] } }Tag for invalidation
RevalidationCodeUse Case
revalidatePath('/​posts')PathAfter mutation
revalidateTag('posts')TagInvalidate tagged data
router.refresh()ClientRefresh current route

When to Use This Skill

Use for caching and revalidation:

  • Understanding Next.js caching behavior
  • Configuring fetch caching strategies
  • Setting up Incremental Static Regeneration (ISR)
  • Implementing on-demand revalidation
  • Debugging cache issues

Related skills:

  • For data fetching: see nextjs-data-fetching
  • For Server Actions: see nextjs-server-actions
  • For static generation: see nextjs-deployment

Next.js Caching

Caching Overview

Next.js has four caching mechanisms:

MechanismWhatWherePurposeDuration
Request MemoizationReturn values of functionsServerAvoid duplicate requests in component treePer-request
Data CacheDataServerStore data across requests and deploymentsPersistent
Full Route CacheHTML and RSC payloadServerReduce rendering costPersistent
Router CacheRSC payloadClientReduce server requests on navigationSession

Request Memoization

Automatic Deduplication

// This is automatically memoized - only one fetch happens
async function getUser(id: string) {
  const res = await fetch(`https://api.example.com/​users/​${id}`);
  return res.json();
}

// Layout uses getUser
export default async function Layout({ children }: { children: React.ReactNode }) {
  const user = await getUser('1'); // First call - fetches
  return <div>{children}</​div>;
}

// Page also uses getUser
export default async function Page() {
  const user = await getUser('1'); // Second call - uses cached result
  return <div>{user.name}</​div>;
}

Manual Memoization with cache()

import { cache } from 'react';

// For non-fetch functions like database queries
export const getUser = cache(async (id: string) => {
  return db.users.findUnique({ where: { id } });
});

// Both will use the same cached result
const user1 = await getUser('1');
const user2 = await getUser('1');

Data Cache

Caching with fetch()

// Cached indefinitely (default)
const data = await fetch('https://api.example.com/​data');

// Opt out of caching
const data = await fetch('https://api.example.com/​data', {
  cache: 'no-store',
});

// Time-based revalidation
const data = await fetch('https://api.example.com/​data', {
  next: { revalidate: 3600 }, // Revalidate every hour
});

// Tag-based caching
const data = await fetch('https://api.example.com/​posts', {
  next: { tags: ['posts'] },
});

unstable_cache for Non-Fetch

import { unstable_cache } from 'next/​cache';

const getCachedUser = unstable_cache(
  async (userId: string) => {
    return db.users.findUnique({ where: { id: userId } });
  },
  ['user'], // Cache key parts
  {
    revalidate: 3600, // 1 hour
    tags: ['users'],
  }
);

export default async function UserPage({ params }: { params: { id: string } }) {
  const user = await getCachedUser(params.id);
  return <div>{user?.name}</​div>;
}

Route Segment Config

// Opt entire route out of caching
export const dynamic = 'force-dynamic';

// Set revalidation for entire route
export const revalidate = 60; // seconds

// Disable cache for all fetches in route
export const fetchCache = 'force-no-store';

// Force static generation
export const dynamic = 'force-static';

Revalidation

Time-Based Revalidation

// Fetch with revalidation
const data = await fetch('https://api.example.com/​data', {
  next: { revalidate: 60 }, // Revalidate after 60 seconds
});

// Route-level revalidation
export const revalidate = 60;

On-Demand Revalidation

// app/​actions.ts
'use server';

import { revalidatePath, revalidateTag } from 'next/​cache';

// Revalidate a specific path
export async function updatePost(id: string, data: FormData) {
  await db.posts.update({ where: { id }, data: { /​* ... */ } });

  // Revalidate the specific post page
  revalidatePath(`/​posts/​${id}`);

  // Revalidate the posts list
  revalidatePath('/​posts');
}

// Revalidate by tag
export async function createPost(data: FormData) {
  await db.posts.create({ data: { /​* ... */ } });

  // All fetches with 'posts' tag will be revalidated
  revalidateTag('posts');
}

Revalidation API Route

// app/​api/​revalidate/​route.ts
import { revalidatePath, revalidateTag } from 'next/​cache';
import { NextRequest, NextResponse } from 'next/​server';

export async function POST(request: NextRequest) {
  const secret = request.headers.get('x-revalidate-secret');

  if (secret !== process.env.REVALIDATION_SECRET) {
    return NextResponse.json({ error: 'Invalid secret' }, { status: 401 });
  }

  const body = await request.json();

  if (body.tag) {
    revalidateTag(body.tag);
  }

  if (body.path) {
    revalidatePath(body.path);
  }

  return NextResponse.json({ revalidated: true, now: Date.now() });
}

Tag-Based Caching

// Fetch with tags
async function getPosts() {
  const res = await fetch('https://api.example.com/​posts', {
    next: { tags: ['posts', 'content'] },
  });
  return res.json();
}

async function getPost(id: string) {
  const res = await fetch(`https://api.example.com/​posts/​${id}`, {
    next: { tags: ['posts', `post-${id}`] },
  });
  return res.json();
}

// Revalidate all posts
revalidateTag('posts');

// Revalidate specific post
revalidateTag('post-123');

// Revalidate all content
revalidateTag('content');

Full Route Cache

Static Routes

// Automatically cached at build time
export default async function StaticPage() {
  const data = await getData();
  return <div>{data}</​div>;
}

// Force static
export const dynamic = 'force-static';

Dynamic Routes with generateStaticParams

// app/​posts/[slug]/​page.tsx
export async function generateStaticParams() {
  const posts = await db.posts.findMany({ select: { slug: true } });
  return posts.map((post) => ({ slug: post.slug }));
}

// Pages are pre-rendered at build time
export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  return <article>{post.content}</​article>;
}

Opting Out

// Dynamic route - not cached
export const dynamic = 'force-dynamic';

// Or use dynamic functions
import { headers, cookies } from 'next/​headers';

export default async function Page() {
  const headersList = await headers(); // Makes route dynamic
  return <div>...</​div>;
}

Router Cache (Client-Side)

Prefetching

import Link from 'next/​link';

// Prefetch on hover (default)
<Link href="/​about">About</​Link>

// Disable prefetching
<Link href="/​dashboard" prefetch={false}>Dashboard</​Link>

Invalidating Router Cache

'use client';

import { useRouter } from 'next/​navigation';

export function RefreshButton() {
  const router = useRouter();

  const handleRefresh = () => {
    // Refresh current route and invalidate cache
    router.refresh();
  };

  return <button onClick={handleRefresh}>Refresh</​button>;
}

revalidatePath and Router Cache

// Server Action
'use server';

import { revalidatePath } from 'next/​cache';

export async function updateData() {
  // Update data in database
  await db.data.update({ /​* ... */ });

  // This also clears the Router Cache for this path
  revalidatePath('/​data');
}

Cache Headers

Route Handler Caching

// app/​api/​data/​route.ts
import { NextResponse } from 'next/​server';

export async function GET() {
  const data = await fetchData();

  return NextResponse.json(data, {
    headers: {
      'Cache-Control': 'public, s-maxage=3600, stale-while-revalidate=86400',
    },
  });
}

generateStaticParams with Dynamic

// Generate some pages statically, allow others dynamically
export async function generateStaticParams() {
  // Only pre-render the top 100 posts
  const posts = await db.posts.findMany({ take: 100 });
  return posts.map((post) => ({ slug: post.slug }));
}

// Allow dynamic rendering for posts not in generateStaticParams
export const dynamicParams = true; // default

// Or 404 for unknown slugs
export const dynamicParams = false;

Caching Strategies

Stale-While-Revalidate Pattern

// Serve cached content while revalidating in background
const data = await fetch('https://api.example.com/​data', {
  next: { revalidate: 60 },
});

// First request after 60s: serves stale, triggers revalidation
// Subsequent requests: serve fresh data

Cache-First Strategy

// Cache indefinitely, revalidate on-demand
const data = await fetch('https://api.example.com/​static-data');
// Use revalidateTag('static-data') when data changes

Network-First Strategy

// Always fetch fresh data
const data = await fetch('https://api.example.com/​realtime', {
  cache: 'no-store',
});

Debugging Cache

Cache Status Headers

// Enable cache debugging
// next.config.js
module.exports = {
  logging: {
    fetches: {
      fullUrl: true,
    },
  },
};

Check Cache Hit/​Miss

// In development, check terminal for cache status
// HIT - served from cache
// MISS - fetched from origin
// STALE - served stale, revalidating

Best Practices

PracticeDescription
Use tags for related dataGroup related fetches with tags
Revalidate minimallyOnly revalidate what changed
Prefer static generationUse generateStaticParams when possible
Cache database queriesUse unstable_cache for non-fetch
Set appropriate TTLBalance freshness vs performance
Use ISR for contentTime-based revalidation for content sites

More skills from JosiahSiegel

debugging-troubleshooting-2025 logo
JosiahSiegel/claude-plugin-marketplace

debugging-troubleshooting-2025

Comprehensive bash script debugging and troubleshooting techniques for 2025. PROACTIVELY activate for: (1) debugging a misbehaving bash script, (2) using set -x, set -e, set -u, set -o pipefail (strict mode), (3) customizing PS4 for richer trace output, (4) trap DEBUG, ERR, and EXIT for diagnosti...

58 0
View
tailwindcss-accessibility logo
JosiahSiegel/claude-plugin-marketplace

tailwindcss-accessibility

Tailwind CSS accessibility patterns including WCAG 2.2 compliance, touch targets, focus management, and ARIA. PROACTIVELY activate for: (1) building accessible UI with Tailwind, (2) WCAG 2.2 compliance (Level A, AA, AAA), (3) focus rings and focus-visible styling, (4) minimum touch-target sizes (...

58 0
View
sql-server-2025 logo
JosiahSiegel/claude-plugin-marketplace

sql-server-2025

SQL Server 2025 and SqlPackage 170.2.70 (October 2025) — vector databases, AI integration, and modern features. PROACTIVELY activate for: (1) SQL Server 2025 features, (2) vector type and vector indexes for AI, (3) Vector functions (VECTOR_DISTANCE, etc.), (4) AI integration (Azure OpenAI, embedd...

58 0
View
adf-master logo
JosiahSiegel/claude-plugin-marketplace

adf-master

Azure Data Factory (ADF) CI/CD, deployment, and pipeline development. PROACTIVELY activate for: (1) ADF CI/CD setup (npm validation, ARM template export), (2) ADF ARM template deployment, (3) ADF npm build validation in CI, (4) PrePostDeploymentScript for trigger and resource cleanup, (5) ADF Git...

58 0
View
powershell-security logo
JosiahSiegel/claude-plugin-marketplace

powershell-security

Modern PowerShell security practices for 2025 — SecretManagement, JEA, WDAC, credential protection. PROACTIVELY activate for: (1) Microsoft.PowerShell.SecretManagement and SecretStore for credential storage, (2) Just Enough Administration (JEA) endpoints, (3) Windows Defender Application Control ...

58 0
View
nextjs-middleware logo
JosiahSiegel/claude-plugin-marketplace

nextjs-middleware

Complete Next.js Middleware system (Next.js 15.5/16). PROACTIVELY activate for: (1) Creating middleware.ts (Edge) or proxy.ts (Node.js), (2) Matcher configuration, (3) Authentication protection, (4) Role-based access control, (5) Redirects and rewrites, (6) Internationalization (i18n), (7) Securi...

58 0
View
nextjs-data-fetching logo
JosiahSiegel/claude-plugin-marketplace

nextjs-data-fetching

Complete Next.js data fetching system (Next.js 15.5/16). PROACTIVELY activate for: (1) Server Component data fetching, (2) Parallel and sequential fetching, (3) Streaming with Suspense, (4) Route Handlers (API routes), (5) Client-side fetching with SWR/TanStack Query, (6) generateStaticParams for...

58 0
View
advanced-features-2025 logo
JosiahSiegel/claude-plugin-marketplace

advanced-features-2025

Advanced Claude Code plugin features for hooks, MCP integration, team distribution, and progressive disclosure. PROACTIVELY activate for: (1) progressive disclosure design, (2) hook automation, (3) PreToolUse and PostToolUse hooks, (4) MCP server integration, (5) .mcp.json configuration, (6) team...

58 0
View
azure-sql-optimization logo
JosiahSiegel/claude-plugin-marketplace

azure-sql-optimization

Azure SQL Database optimization and platform-specific features. PROACTIVELY activate for: (1) Azure SQL Database optimization, (2) DTU vs vCore selection and right-sizing, (3) automatic tuning (force last good plan, create/drop index), (4) Hyperscale tier and read replicas, (5) Serverless tier an...

58 0
View
github-actions-2025 logo
JosiahSiegel/claude-plugin-marketplace

github-actions-2025

GitHub Actions 2025-2026 features and modernization. PROACTIVELY activate for: (1) 1 vCPU Linux runners (October 2025 public preview), (2) immutable releases for hardened distribution, (3) Node24 migration from Node20, (4) reusable workflows and composite actions, (5) workflow_dispatch with rich ...

58 0
View
git-2-49-features logo
JosiahSiegel/claude-plugin-marketplace

git-2-49-features

Git 2.49 specific features and performance improvements. PROACTIVELY activate for: (1) git-backfill command (new in 2.49) for partial clones, (2) path-walk API improvements, (3) zlib-ng integration for faster compression, (4) reftables backend stabilization, (5) revision-walk performance, (6) bun...

58 0
View
vitest-3-features logo
JosiahSiegel/claude-plugin-marketplace

vitest-3-features

Vitest 3 features and migration from Vitest 2 (2025). PROACTIVELY activate for: (1) Vitest 3 stable features, (2) workspace mode for monorepos, (3) test annotations and reporter API, (4) projects configuration, (5) browser mode in Vitest 3, (6) inline snapshots and toMatchInlineSnapshot, (7) type...

58 0
View

Popular AI tools

Kaiber logo
Video

Kaiber

Generate, edit, and beat-sync AI video with leading models in one workspace.

Paid
View
Vimcal logo
Productivity

Vimcal

The world's fastest calendar for remote work

Free
View

Transform Your Design with AI Designer by ImgCreator.ai

Freemium
View
Akool AI logo
Content & writing

Akool AI

Revolutionizing Video Production with AI-Powered Creativity

Paid
View

Extend an image past the frame and let AI fill the new aspect ratio.

Freemium
View
StarByFace logo
Security

StarByFace

Discover your celebrity doppelgänger with StarByFace!

Free
View
C

ChainClarity explains 700+ crypto whitepapers in plain English, with layered summaries, comparisons, research tools, alerts, and a $4.99 Pro plan.

Freemium
View
Opus Clip logo
Coding & apps

Opus Clip

Opus.ai: Revolutionize Your Web Experience

Free
View