Next.js

Data Caching

Caching data fetches, revalidating paths, and using unstable_cache in the App Router.

Fetch Cache: Using the extended fetch API to cache and revalidate requests.
📄app/lib/data.ts
TypeScript
export async function getPosts() {
  // Cache the response indefinitely, tag it for on-demand revalidation
  const res = await fetch('https://api.example.com/posts', {
    cache: 'force-cache',
    next: { tags: ['posts'] },
  });

  if (!res.ok) throw new Error('Failed to fetch data');
  return res.json();
}

export async function getTime() {
  // Revalidate the cache every 60 seconds (Time-based Revalidation)
  const res = await fetch('https://worldtimeapi.org/api/timezone/Europe/London', {
    next: { revalidate: 60 },
  });
  
  return res.json();
}
Unstable Cache: Caching expensive database queries directly.
📄app/lib/db-cache.ts
TypeScript
import { unstable_cache } from 'next/cache';
import db from './db';

// Cache database query results
export const getCachedUser = unstable_cache(
  async (id: string) => {
    return await db.user.findUnique({ where: { id } });
  },
  ['user-cache-key'], // cache key parts
  {
    revalidate: 3600, // Revalidate every hour
    tags: ['users'], // Tag for on-demand revalidation
  }
);
On-Demand Revalidation: Revalidating cached data manually via a Server Action.
📄app/actions.ts
TypeScript
'use server';

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

export async function updatePost(formData: FormData) {
  // Update data in your database
  // await db.post.update(...)

  // Revalidate by tag (clears fetch cache tagged with 'posts')
  revalidateTag('posts');

  // Or revalidate a specific path
  revalidatePath('/blog');
}