Let's look at how Next.js handles route caching for API routes.
Examining API Route Caching
We'll start by creating a new API route in our Next.js application. In the app
directory, create a file named time/route.ts
. This file will define a simple API route handler using the route.ts
file naming convention:
// inside app/time/route.ts
import { NextResponse } from "next/server";
export async function GET() {
console.log(`GET /time ${new Date().toLocaleTimeString()}`);
return NextResponse.json({ time: new Date().toLocaleTimeString() });
}
For now, this route handles GET
requests and returns a JSON response with the current time.
Build and run our Next.js application, and then navigate to /time
in the browser:
Refreshing the page multiple times, you'll notice that the timestamp remains the same. Next.js has cached our API route and is treating it as a static route.
Forcing Dynamic Behavior in API Routes
Next.js automatically caches API routes that don't perform actions that would prevent caching, such as data fetching or mutations. In many cases, you'll want your API routes to be dynamic. Let's fix that.
Just like with page routes, we have several options to override this default caching behavior and ensure our route returns fresh data on each request:
unstable_noStore
: Instructs the browser and CDN to not cache the response at all.headers
: Allows you to set custom caching headers, providing fine-grained control over caching behavior.cookies
: Determines caching based on the presence or values of specific cookies.export const dynamic = "force-dynamic"
: Explicitly tells Next.js to treat the route as dynamic.
For API routes that we want to be statically generated but also want to update periodically, we can use the revalidate
option. This option allows you to specify how often, in seconds, the route should revalidate and fetch fresh data:
// app/time/route.ts
import { NextResponse } from 'next/server'
export const revalidate = 2
export async function GET() {
...
With this configuration, our API route will still be statically generated, but it will revalidate every 2 seconds. This ensures that users will see relatively up-to-date information without having to wait for a full page reload.
Dynamic Behavior with POST
, PUT
, and DELETE
One important thing to remember is that exporting a POST
, PUT
, or DELETE
handler from your API route file automatically makes the route dynamic.
To illustrate this, let's add a POST
handler to our existing time
route:
// inside app/time/route.ts
export async function POST() {
console.log(`POST /time ${new Date().toLocaleTimeString()}`);
return NextResponse.json({ time: new Date().toLocaleTimeString() });
}
Even with revalidate
set, the presence of the POST
handler will force the route to be dynamic. This ensures that any mutations or data updates performed by these HTTP methods are reflected correctly.
That covers the full route cache in Next.js and how it applies to both page and API routes. Next, we'll explore the data cache and how it can be used to optimize data fetching in our applications.