Next.js - Caching



Caching is an optimization technique used in web applications. Next.js provides several caching mechanisms to improve performance and reduce load times. In this chapter, we will learn all about caching in Next.js and how to use it to improve performance of applications.

What is Caching?

Caching is a technique used in web applications to store data in server memory or on client browser so that it can be accessed quickly. Caching is used to reduce load times, improve performance, and reduce server load. Next.js provides several caching mechanisms to store cache data on the server and client side.

Caching Mechanisms in Next.js

Next.js provides several caching mechanisms to improve performance and reduce load times. Here are some of the caching mechanisms available in Next.js:

Mechanism Description Used on
Request Memoization The request memoization caching is used to re-use data in a React Component tree by automatically duplicating identical data requests during the same render cycle, preventing duplicate data fetching. Server
Data Cache The data cache is used to store results of fetch requests on the server and re-use it across multiple pages. This cache persists across multiple user requests and server renders. Server
Full Route Cache The full route cache is used to cache the entire HTML page on the server and serve it to the client. Server
Router Cache The router cache is used to cache the entire page on the client side and serve it to the user. This cache will enable instant back/forward navigation. Client

Caching Behavior of Next.js Function

Next.js provides several functions to cache data on the server and client side. Here are some of the caching functions available in Next.js:

Caching in fetch Function

The fetch function in Next.js is used to fetch data from an API endpoint. The Data returned from fetch is not automatically cached in the Data Cache. Which means, By default, the caching behavior of fetch is same as setting cache to 'no-store'.

// Disable caching (default behavior)
let data = await fetch(`link/to/api`, { cache: 'no-store' })

// Opt into caching
let data = await fetch(`link/to/api`, { cache: 'force-cache' })

// Revalidate cache at most after 1 hour
let data = await fetch(`link/to/api`, { next: { revalidate: 3600 }})

Caching in useRouter Function

The useRouter function in Next.js is used to access the router object. The router object provides several options to cache data on the client side. Here are some of the caching options available in useRouter:

import { useRouter } from 'next/router'

export default function Page() {
  const router = useRouter()

  // Prefetch a route
  router.prefetch('/products')

  // Refresh the current route
  router.refresh()
}

The router.prefetch is an option of useRouter hook, which is used to manually prefetch a route. This function will prefetch routes before the user navigates to them and add the route to the Router Cache at client side, so that the page loads faster when the user visits the route.

The router.refresh is an option of useRouter Hook, which is used to manually refresh a route. This completely clears the Router Cache, and makes a new request to the server for the current route. The refresh does not affect the Data or Full Route Cache. The rendered result will be reconciled on the client while preserving React state and browser state.

Caching in generateStaticParams Function

The generateStaticParams function in Next.js is used to generate static parameters for a dynamic pages. For this types of dynamic pages (e.g. app/blog/[slug]/page.js), the path provided by `generateStaticParams` are cached in the Full Route Cache at build time. At request time, Next.js will also cache paths that weren't known at build time the first time they're visited.

export async function getStaticPaths() {
  const paths = await generateStaticParams()
  return { paths, fallback: true }
}

Caching in Link Component

The <Link> component in Next.js is used to navigate between pages. By default, the <Link> component automatically prefetches routes from the Full Route Cache and adds the React Server Component Payload to the Router Cache. To disable prefetching, you can set the prefetch prop to false. But this will not skip the cache permanently, the route segment will still be cached client-side when the user visits the route.

import Link from 'next/link'

export default function Page() {
  return (
    <Link href="/products" prefetch={false}>
      <a>Products</a>
    </Link>
  )
}

Example of Next.js Caching

In the following example, we have a page that fetches data from an API and caches it on the server and client side. The data is fetched using the fetch function and cached using the Data Cache and Router Cache. The data is then displayed on the page using the useRouter hook and Link component.

// app/page.tsx
"use client"

import Link from 'next/link'
import { useEffect, useState } from 'react'

export default function Page() {
  const [data, setData] = useState([])

  useEffect(() => {
    async function fetchData() {
      let data = await fetch('https://jsonplaceholder.typicode.com/users', {
        cache: 'force-cache'
      }).then(res => res.json())

      setData(data)
    }

    fetchData()
  }, [])

  return (
    <div>
        {data.map(user => (
            <div key={user.id}>
                <h4>{user.name}</h4>
            </div>
        ))}
    </div>
  )
}

Output

In the output below, you can see that on reloading the page API response is rendered instantaneously. This is because the data is cached on the server and client side, and is re-used across multiple pages.

Next.js Caching
Advertisements