NextjsRequest Memoization

Request Memoization

In a typical page, a layout, the page itself, and several nested components might all need the same piece of data — the current user, for example. Without any special handling, that could mean the same fetch call runs several times over during a single render. React and Next.js solve this with request memoization: identical fetch calls made during the same render pass are automatically deduplicated.

The problem it solves

Imagine a layout and a page that each independently need the logged-in user's profile, without either one passing it down as a prop.

TSX
// app/[locale]/dashboard/layout.tsx
async function getUser() {
  const res = await fetch('https://api.example.com/me')
  return res.json()
}

export default async function DashboardLayout({ children }: { children: React.ReactNode }) {
  const user = await getUser()

  return (
    <div>
      <p>Welcome, {user.name}</p>
      {children}
    </div>
  )
}

TSX
// app/[locale]/dashboard/page.tsx
async function getUser() {
  const res = await fetch('https://api.example.com/me')
  return res.json()
}

export default async function DashboardPage() {
  const user = await getUser()

  return <h1>{user.name}&apos;s Dashboard</h1>
}

Both getUser functions call fetch with the exact same URL and options. Naively, that would be two separate network round trips for identical data during the render of a single page. Instead, React memoizes the result: the layout's call actually performs the fetch, and the page's call — being identical in URL and options — receives the same cached Promise without triggering a second network request.

Scoped to one request, not persisted across requests

Request memoization only lasts for the duration of a single server render — one incoming request. It is not the same as the Data Cache, which can persist across many different requests and even across deployments. Once the response has been sent, the memoization cache for that render is discarded.

Mechanism

Scope

Applies to

Request Memoization

A single render pass (one request)

fetch() calls with identical URL + options

Data Cache

Across requests, and across deployments by default

fetch() calls, based on cache/revalidate/tags options

Note
Because request memoization is scoped to one render, it does not create the risk of serving one user's data to another — each incoming request gets its own fresh memoization cache.
Only fetch is memoized automatically
Warning
Request memoization is a feature of the extended fetch() API. If you fetch data with a database client, an ORM, or an SDK that does not go through fetch, those calls are not automatically deduplicated. Use React's cache() function to get the same deduplication behavior for arbitrary functions — see the Preloading Data page for a worked example.

TSX
import { cache } from 'react'
import { db } from '@libs/db'

// Wrapping a non-fetch data access function with cache() gives it
// the same per-request deduplication that fetch() gets automatically.
export const getUser = cache(async (id: string) => {
  return db.user.findUnique({ where: { id } })
})
Why this matters
  • You can call the same data-fetching function from a layout, a page, and any nested Server Component without worrying about duplicate network requests.

  • It encourages colocating data requirements with the components that use them, instead of fetching once at the top and drilling props down through many layers.

  • It only works for calls with matching URL and options — even a differently ordered header or a different query parameter creates a separate, non-deduplicated entry.

Tip
If you notice a data-fetching function being called from several places in the same route tree, that is exactly the pattern request memoization is designed for — no extra work needed as long as it goes through fetch (or cache() for non-fetch data sources).