Skip to content
Watch the complete Next.js 15 course on YouTube

Caching route handlers

This page explains how caching works in Next.js route handlers.

Understanding route handler caching

Route handlers in Next.js aren’t cached by default. However, you can opt into caching when using the GET method to improve performance for responses that don’t change frequently.

Default behavior (no caching)

By default, route handlers execute on every request:

app/time/route.ts
export async function GET() {
return Response.json({ time: new Date().toLocaleTimeString() });
}

This endpoint returns the current time in JSON format. Each request shows the latest time since there’s no caching by default.

Enabling caching

To enable caching for a route handler, add the dynamic configuration option:

app/categories/route.ts
export const dynamic = "force-static";
export async function GET() {
// This data would typically come from a database
const categories = [
{ id: 1, name: "Electronics" },
{ id: 2, name: "Books" },
{ id: 3, name: "Clothing" },
{ id: 4, name: "Home & Garden" },
];
return Response.json(categories);
}

With export const dynamic = 'force-static', the response is cached at build time and served instantly to all users. This is ideal for data that rarely changes.

Caching behavior in development vs production

Caching behavior differs between development and production environments:

  • In development (npm run dev): Caching is disabled to make development easier
  • In production (npm run build and npm run start): Caching is enabled according to your configuration

Revalidating cached data

You can revalidate cached data using Incremental Static Regeneration (ISR) by adding the revalidate option:

app/time/route.ts
export const dynamic = "force-static";
export const revalidate = 10; // Revalidate every 10 seconds
export async function GET() {
return Response.json({ time: new Date().toLocaleTimeString() });
}

When you set revalidate = 10:

  1. The route handler is cached at build time
  2. All requests within the 10-second window receive the cached response
  3. After 10 seconds, the next request still receives the cached (stale) response
  4. In the background, Next.js generates a new version with fresh data
  5. Subsequent requests receive the updated data for the next 10 seconds

Caching limitations

Caching in route handlers has several limitations:

  • Only works with GET methods
  • Other HTTP methods (POST, PUT, DELETE, etc.) are never cached
  • Caching is disabled when using dynamic functions like headers() and cookies()
  • Caching is disabled when accessing the Request object in your GET method

Example: Time API with caching

Here’s a complete example of a time API with caching and revalidation:

app/time/route.ts
export const dynamic = "force-static";
export const revalidate = 60; // Revalidate every minute
export async function GET() {
const timestamp = new Date().toLocaleTimeString();
console.log(`Generating time: ${timestamp}`);
return Response.json({
time: timestamp,
message: "This response is cached and revalidated every minute",
});
}

Good to know

  • Caching improves performance by reducing server load and response time
  • Choose appropriate revalidation intervals based on how frequently your data changes
  • For truly dynamic data that changes on every request, avoid caching
  • In development, you won’t see caching effects regardless of your configuration
  • To test caching behavior, you need to build and start your application in production mode