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:
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:
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
andnpm 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:
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
:
- The route handler is cached at build time
- All requests within the 10-second window receive the cached response
- After 10 seconds, the next request still receives the cached (stale) response
- In the background, Next.js generates a new version with fresh data
- 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()
andcookies()
- 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:
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