ProNextJS
    Professional Next.js Course
    Loading price
    30-Day Money-Back Guarantee
    lesson

    Next.js API Route Caching

    Jack HerringtonJack Herrington

    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:

    the time route

    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.

    Transcript

    So the full route cache applies to page routes, does it also apply to API routes? Let's take a look. To do that, I'm going to create a new route over in the app directory called time. It's going to be a route handler route, so I'm going to use route.ts. In that route handler, I'm going to define a get method that will respond to a get request.

    We'll do a console log and we'll just return a JSON payload with a time. Okay, let's build and run this. And then over on my browser, I'll go to slash time. And now if I refresh, I always get the same time back. Why is that?

    Well, that's because Next.js has taken a look at that slash time route and decided that it is a static route. Even though it's an API route, we're not doing anything in there that couldn't be cached. So it is decided that it is a static route. Now, that's not what you want. Again, You've got the options of doing a no store, or headers, or cookies, or you can export that dynamic const, and say that you want it to be forced to be dynamic.

    You can also even do the revalidation thing. So in this case, we'll revalidate every two seconds, but of course we need to be static for that, so we need to get rid of anything that would indicate otherwise. Let's give that a try. Now we can see that slash time is still marked as static. And if I go back over to my browser and I refresh, and then a couple of seconds later I hit refresh again, we can see that we get new values.

    One more thing that might trip you up here is if you want a static page, let's keep that as static, and we'll add a post in here that does exactly the same thing. So it should be static, right? But it's actually not. If you export a post, a put, or a delete from your route, then it will actually turn it into a dynamic route. So we'll take a look at our table, and we can see that we get the F, which in this case means that we are a dynamic route.

    So that's the full route cache. There are other caches as well including the data cache and we'll take a look at that next.