Next.js - Full Route Caching



In this chapter, we will learn Full Route Caching in Next.js, how it works, and how to completely clear full route cache.

What is Full Route Caching?

Full Route Caching is Next.js's default caching behavior where it statically generates and caches entire routes at build time. This optimization technique allows to serve the cached route instead of rendering on the server for every request, resulting in faster page loads.

How it Works?

  • When app is build for deployment, Next.js automatically caches the entire route segment, including the layout, page, and metadata.
  • Each cached route is served as static HTML to users
  • The cache persists across deployments unless invalidated in the code.

Invalidate Full Route Cache

Full Route Caching can be invalidated in two ways:

  • Revalidating Data: Revalidating the Data Cache, will in turn invalidate the Router Cache by re-rendering components on the server and caching the new render output.
  • Redeploying: Redeploying the App with a new build will clear all Routing caches. ( Only Data-Cache persists across deployment )

Clear Full Route Cache

Whether a route is cached or not at build time depends on whether it's statically or dynamically rendered. Static routes are cached by default, whereas dynamic routes are rendered at request time, and not cached. You can opt out of the Full Route Cache, or in other words, dynamically render components for every incoming request, by:

Using Force Dynamic

Force Dynamic is a technique used to opt out of Full Route Caching. It forces Next.js to render the page at request time, instead of serving the cached static HTML.

In the code snippet below, we have a dynamic page that displays a random data. We will display the random data with timestamp on the page.

// Set as force dynamic page
export const dynamic = 'force-dynamic'

async function getData() {
  // Simulating an API call with random data to demonstrate no caching
  const randomNumber = Math.floor(Math.random() * 100)
  return {
    timestamp: new Date().toISOString(),
    randomNumber
  }
}

export default async function Home() {
  const data = await getData()

  return (
    <main>
      <h1>Force Dynamic Example</h1>
      <div>
        <p>Timestamp: {data.timestamp}</p>
        <p>Random Number: {data.randomNumber}</p>
      </div>
      
    </main>
  )
}

Output

The image below shows the output of the code snippet above. When we refresh the page, we are getting a different random number for each request. This is because the page is dynamically rendered at request time, and not cached.

Next.js Force Dynamic
Note: In development mode, you may not see the effect of force-dynamic, this is because Next.js automatically disables most caching to make development easier. To see caching effect, you have to build the app and start the production server.

Using Dynamic APIs

Dynamic APIs are server-side rendered APIs that are not cached at build time. The page containing dynamic APIs will be forcefully fetched from server. In the section below, we will setup a dynamic API that sets a cookie based on the theme selected by the user.

// Set up the cookie (Run in terminal)
Invoke-WebRequest -Uri "http://localhost:3000/api/set-cookie" -Headers @{theme="dark"} -Method GET

In the code snippet below, we have a dynamic API that sets a cookie based on the theme selected by the user. when we access the page, with different search parameters, we'll see them reflected in the output. This route will always be dynamically rendered because it uses runtime request information, which means no static HTML generated at build time.

// app/api/set-cookie/route.ts

import { cookies } from 'next/headers'
import { NextResponse } from 'next/server'

export async function GET(request: Request) {
  const theme = request.headers.get('theme') || 'light'
  
  // Wait for the cookieStore
  const cookieStore = await cookies()
  cookieStore.set('theme', theme)
  
  return NextResponse.json({ message: 'Cookie set successfully' })
}

// app/dynamic-data/page.tsx

import { cookies, headers } from 'next/headers'

export default function DynamicPage({searchParams,}: { searchParams: { [key: string]: string | string[] | undefined }})  {
    const cookieStore = cookies()
    const headersList = headers()

    // Get specific cookie
    const theme = cookieStore.get('theme')
    
    // Get specific header
    const userAgent = headersList.get('user-agent')
    const referer = headersList.get('referer')

    return (
        <div "p-4">
        <h1>Dynamic Data Example</h1>
        
        <div">
            {/* Display Search Parameters */}
            <section>
            <h2>Search Parameters:</h2>
            <pre>
                {JSON.stringify(searchParams, null, 2)}
            </pre>
            </section>

            {/* Display Cookies */}
            <section>
            <h2>Cookies:</h2>
            <div>
                <p>Theme Cookie: {theme?.value || 'Not set'}</p>
                <p>All Cookies:</p>
                <pre>
                {JSON.stringify(cookieStore.getAll(), null, 2)}
                </pre>
            </div>
            </section>
        </div>
        </div>
    )
}

Output

The image below shows the output of the code snippet above. The search parameters are displayed in the first section, and the cookies are displayed in the second section. For each request, a new page is rendered with the search parameters and cookies displayed.

Next.js Dynamic API
Advertisements