mirror of
https://github.com/hanzoai/next.js.git
synced 2026-10-30 14:46:38 +00:00
Clarify that fetch is not cached when used in a Server Action (see https://github.com/vercel/next.js/pull/60170), and in `POST` requests in Route Handlers.
309 lines
14 KiB
Plaintext
309 lines
14 KiB
Plaintext
---
|
|
title: Data Fetching, Caching, and Revalidating
|
|
nav_title: Fetching, Caching, and Revalidating
|
|
description: Learn how to fetch, cache, and revalidate data in your Next.js application.
|
|
---
|
|
|
|
Data fetching is a core part of any application. This page goes through how you can fetch, cache, and revalidate data in React and Next.js.
|
|
|
|
There are four ways you can fetch data:
|
|
|
|
1. [On the server, with `fetch`](#fetching-data-on-the-server-with-fetch)
|
|
2. [On the server, with third-party libraries](#fetching-data-on-the-server-with-third-party-libraries)
|
|
3. [On the client, via a Route Handler](#fetching-data-on-the-client-with-route-handlers)
|
|
4. [On the client, with third-party libraries](#fetching-data-on-the-client-with-route-handlers).
|
|
|
|
## Fetching Data on the Server with `fetch`
|
|
|
|
Next.js extends the native [`fetch` Web API](https://developer.mozilla.org/docs/Web/API/Fetch_API) to allow you to configure the [caching](#caching-data) and [revalidating](#revalidating-data) behavior for each fetch request on the server. React extends `fetch` to automatically [memoize](/docs/app/building-your-application/data-fetching/patterns#fetching-data-where-its-needed) fetch requests while rendering a React component tree.
|
|
|
|
You can use `fetch` with `async`/`await` in Server Components, in [Route Handlers](/docs/app/building-your-application/routing/route-handlers), and in [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations).
|
|
|
|
For example:
|
|
|
|
```tsx filename="app/page.tsx" switcher
|
|
async function getData() {
|
|
const res = await fetch('https://api.example.com/...')
|
|
// The return value is *not* serialized
|
|
// You can return Date, Map, Set, etc.
|
|
|
|
if (!res.ok) {
|
|
// This will activate the closest `error.js` Error Boundary
|
|
throw new Error('Failed to fetch data')
|
|
}
|
|
|
|
return res.json()
|
|
}
|
|
|
|
export default async function Page() {
|
|
const data = await getData()
|
|
|
|
return <main></main>
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/page.js" switcher
|
|
async function getData() {
|
|
const res = await fetch('https://api.example.com/...')
|
|
// The return value is *not* serialized
|
|
// You can return Date, Map, Set, etc.
|
|
|
|
if (!res.ok) {
|
|
// This will activate the closest `error.js` Error Boundary
|
|
throw new Error('Failed to fetch data')
|
|
}
|
|
|
|
return res.json()
|
|
}
|
|
|
|
export default async function Page() {
|
|
const data = await getData()
|
|
|
|
return <main></main>
|
|
}
|
|
```
|
|
|
|
> **Good to know**:
|
|
>
|
|
> - Next.js provides helpful functions you may need when fetching data in Server Components such as [`cookies`](/docs/app/api-reference/functions/cookies) and [`headers`](/docs/app/api-reference/functions/headers). These will cause the route to be dynamically rendered as they rely on request time information.
|
|
> - In Route handlers, `fetch` requests are not memoized as Route Handlers are not part of the React component tree.
|
|
> - In [Server Actions](/docs/app/building-your-application/data-fetching/server-actions-and-mutations), `fetch` requests are not cached (defaults `cache: no-store`).
|
|
> - To use `async`/`await` in a Server Component with TypeScript, you'll need to use TypeScript `5.1.3` or higher and `@types/react` `18.2.8` or higher.
|
|
|
|
### Caching Data
|
|
|
|
Caching stores data so it doesn't need to be re-fetched from your data source on every request.
|
|
|
|
By default, Next.js automatically caches the returned values of `fetch` in the [Data Cache](/docs/app/building-your-application/caching#data-cache) on the server. This means that the data can be fetched at build time or request time, cached, and reused on each data request.
|
|
|
|
```js
|
|
// 'force-cache' is the default, and can be omitted
|
|
fetch('https://...', { cache: 'force-cache' })
|
|
```
|
|
|
|
However, there are exceptions, `fetch` requests are not cached when:
|
|
|
|
- Used inside a [Server Action](/docs/app/building-your-application/data-fetching/server-actions-and-mutations).
|
|
- Used inside a [Route Handler](/docs/app/building-your-application/routing/route-handlers) that uses the `POST` method.
|
|
|
|
> **What is the Data Cache?**
|
|
>
|
|
> The Data Cache is a persistent [HTTP cache](https://developer.mozilla.org/docs/Web/HTTP/Caching). Depending on your platform, the cache can scale automatically and be [shared across multiple regions](https://vercel.com/docs/infrastructure/data-cache).
|
|
>
|
|
> Learn more about the [Data Cache](/docs/app/building-your-application/caching#data-cache).
|
|
|
|
### Revalidating Data
|
|
|
|
Revalidation is the process of purging the Data Cache and re-fetching the latest data. This is useful when your data changes and you want to ensure you show the latest information.
|
|
|
|
Cached data can be revalidated in two ways:
|
|
|
|
- **Time-based revalidation**: Automatically revalidate data after a certain amount of time has passed. This is useful for data that changes infrequently and freshness is not as critical.
|
|
- **On-demand revalidation**: Manually revalidate data based on an event (e.g. form submission). On-demand revalidation can use a tag-based or path-based approach to revalidate groups of data at once. This is useful when you want to ensure the latest data is shown as soon as possible (e.g. when content from your headless CMS is updated).
|
|
|
|
#### Time-based Revalidation
|
|
|
|
To revalidate data at a timed interval, you can use the `next.revalidate` option of `fetch` to set the cache lifetime of a resource (in seconds).
|
|
|
|
```js
|
|
fetch('https://...', { next: { revalidate: 3600 } })
|
|
```
|
|
|
|
Alternatively, to revalidate all `fetch` requests in a route segment, you can use the [Segment Config Options](/docs/app/api-reference/file-conventions/route-segment-config).
|
|
|
|
```jsx filename="layout.js | page.js"
|
|
export const revalidate = 3600 // revalidate at most every hour
|
|
```
|
|
|
|
If you have multiple fetch requests in a statically rendered route, and each has a different revalidation frequency. The lowest time will be used for all requests. For dynamically rendered routes, each `fetch` request will be revalidated independently.
|
|
|
|
Learn more about [time-based revalidation](/docs/app/building-your-application/caching#time-based-revalidation).
|
|
|
|
#### On-demand Revalidation
|
|
|
|
Data can be revalidated on-demand by path ([`revalidatePath`](/docs/app/api-reference/functions/revalidatePath)) or by cache tag ([`revalidateTag`](/docs/app/api-reference/functions/revalidateTag)) inside a [Server Action](/docs/app/building-your-application/data-fetching/server-actions-and-mutations) or [Route Handler](/docs/app/building-your-application/routing/route-handlers).
|
|
|
|
Next.js has a cache tagging system for invalidating `fetch` requests across routes.
|
|
|
|
1. When using `fetch`, you have the option to tag cache entries with one or more tags.
|
|
2. Then, you can call `revalidateTag` to revalidate all entries associated with that tag.
|
|
|
|
For example, the following `fetch` request adds the cache tag `collection`:
|
|
|
|
```tsx filename="app/page.tsx" switcher
|
|
export default async function Page() {
|
|
const res = await fetch('https://...', { next: { tags: ['collection'] } })
|
|
const data = await res.json()
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/page.js" switcher
|
|
export default async function Page() {
|
|
const res = await fetch('https://...', { next: { tags: ['collection'] } })
|
|
const data = await res.json()
|
|
// ...
|
|
}
|
|
```
|
|
|
|
You can then revalidate this `fetch` call tagged with `collection` by calling `revalidateTag` in a Server Action:
|
|
|
|
```ts filename="app/actions.ts" switcher
|
|
'use server'
|
|
|
|
import { revalidateTag } from 'next/cache'
|
|
|
|
export default async function action() {
|
|
revalidateTag('collection')
|
|
}
|
|
```
|
|
|
|
```js filename="app/actions.js" switcher
|
|
'use server'
|
|
|
|
import { revalidateTag } from 'next/cache'
|
|
|
|
export default async function action() {
|
|
revalidateTag('collection')
|
|
}
|
|
```
|
|
|
|
Learn more about [on-demand revalidation](/docs/app/building-your-application/caching#on-demand-revalidation).
|
|
|
|
#### Error handling and revalidation
|
|
|
|
If an error is thrown while attempting to revalidate data, the last successfully generated data will continue to be served from the cache. On the next subsequent request, Next.js will retry revalidating the data.
|
|
|
|
### Opting out of Data Caching
|
|
|
|
`fetch` requests are **not** cached if:
|
|
|
|
- The `cache: 'no-store'` is added to `fetch` requests.
|
|
- The `revalidate: 0` option is added to individual `fetch` requests.
|
|
- The `fetch` request is inside a Router Handler that uses the `POST` method.
|
|
- The `fetch` request comes after the usage of `headers` or `cookies`.
|
|
- The `const dynamic = 'force-dynamic'` route segment option is used.
|
|
- The `fetchCache` route segment option is configured to skip cache by default.
|
|
- The `fetch` request uses `Authorization` or `Cookie` headers and there's an uncached request above it in the component tree.
|
|
|
|
#### Individual `fetch` Requests
|
|
|
|
To opt out of caching for individual `fetch` requests, you can set the `cache` option in `fetch` to `'no-store'`. This will fetch data dynamically, on every request.
|
|
|
|
```js filename="layout.js | page.js"
|
|
fetch('https://...', { cache: 'no-store' })
|
|
```
|
|
|
|
View all the available `cache` options in the [`fetch` API reference](/docs/app/api-reference/functions/fetch).
|
|
|
|
#### Multiple `fetch` Requests
|
|
|
|
If you have multiple `fetch` requests in a route segment (e.g. a Layout or Page), you can configure the caching behavior of all data requests in the segment using the [Segment Config Options](/docs/app/api-reference/file-conventions/route-segment-config).
|
|
|
|
However, we recommend configuring the caching behavior of each `fetch` request individually. This gives you more granular control over the caching behavior.
|
|
|
|
## Fetching data on the Server with third-party libraries
|
|
|
|
In cases where you're using a third-party library that doesn't support or expose `fetch` (for example, a database, CMS, or ORM client), you can configure the caching and revalidating behavior of those requests using the [Route Segment Config Option](/docs/app/api-reference/file-conventions/route-segment-config) and React's `cache` function.
|
|
|
|
Whether the data is cached or not will depend on whether the route segment is [statically or dynamically rendered](/docs/app/building-your-application/rendering/server-components#server-rendering-strategies). If the segment is static (default), the output of the request will be cached and revalidated as part of the route segment. If the segment is dynamic, the output of the request will _not_ be cached and will be re-fetched on every request when the segment is rendered.
|
|
|
|
You can also use the experimental [`unstable_cache` API](/docs/app/api-reference/functions/unstable_cache).
|
|
|
|
### Example
|
|
|
|
In the example below:
|
|
|
|
- The React `cache` function is used to [memoize](/docs/app/building-your-application/caching#request-memoization) data requests.
|
|
- The `revalidate` option is set to `3600` in the Layout and Page segments, meaning the data will be cached and revalidated at most every hour.
|
|
|
|
```ts filename="app/utils.ts" switcher
|
|
import { cache } from 'react'
|
|
|
|
export const getItem = cache(async (id: string) => {
|
|
const item = await db.item.findUnique({ id })
|
|
return item
|
|
})
|
|
```
|
|
|
|
```js filename="app/utils.js" switcher
|
|
import { cache } from 'react'
|
|
|
|
export const getItem = cache(async (id) => {
|
|
const item = await db.item.findUnique({ id })
|
|
return item
|
|
})
|
|
```
|
|
|
|
Although the `getItem` function is called twice, only one query will be made to the database.
|
|
|
|
```tsx filename="app/item/[id]/layout.tsx" switcher
|
|
import { getItem } from '@/utils/get-item'
|
|
|
|
export const revalidate = 3600 // revalidate the data at most every hour
|
|
|
|
export default async function Layout({
|
|
params: { id },
|
|
}: {
|
|
params: { id: string }
|
|
}) {
|
|
const item = await getItem(id)
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/item/[id]/layout.js" switcher
|
|
import { getItem } from '@/utils/get-item'
|
|
|
|
export const revalidate = 3600 // revalidate the data at most every hour
|
|
|
|
export default async function Layout({ params: { id } }) {
|
|
const item = await getItem(id)
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```tsx filename="app/item/[id]/page.tsx" switcher
|
|
import { getItem } from '@/utils/get-item'
|
|
|
|
export const revalidate = 3600 // revalidate the data at most every hour
|
|
|
|
export default async function Page({
|
|
params: { id },
|
|
}: {
|
|
params: { id: string }
|
|
}) {
|
|
const item = await getItem(id)
|
|
// ...
|
|
}
|
|
```
|
|
|
|
```jsx filename="app/item/[id]/page.js" switcher
|
|
import { getItem } from '@/utils/get-item'
|
|
|
|
export const revalidate = 3600 // revalidate the data at most every hour
|
|
|
|
export default async function Page({ params: { id } }) {
|
|
const item = await getItem(id)
|
|
// ...
|
|
}
|
|
```
|
|
|
|
## Fetching Data on the Client with Route Handlers
|
|
|
|
If you need to fetch data in a client component, you can call a [Route Handler](/docs/app/building-your-application/routing/route-handlers) from the client. Route Handlers execute on the server and return the data to the client. This is useful when you don't want to expose sensitive information to the client, such as API tokens.
|
|
|
|
See the [Route Handler](/docs/app/building-your-application/routing/route-handlers) documentation for examples.
|
|
|
|
> **Server Components and Route Handlers**
|
|
>
|
|
> Since Server Components render on the server, you don't need to call a Route Handler from a Server Component to fetch data. Instead, you can fetch the data directly inside the Server Component.
|
|
|
|
## Fetching Data on the Client with third-party libraries
|
|
|
|
You can also fetch data on the client using a third-party library such as [SWR](https://swr.vercel.app/) or [TanStack Query](https://tanstack.com/query/latest). These libraries provide their own APIs for memoizing requests, caching, revalidating, and mutating data.
|
|
|
|
> **Future APIs**:
|
|
>
|
|
> `use` is a React function that **accepts and handles a promise** returned by a function. Wrapping `fetch` in `use` is currently **not** recommended in Client Components and may trigger multiple re-renders. Learn more about `use` in the [React docs](https://react.dev/reference/react/use).
|