Files
next.js/errors/next-prerender-dynamic-metadata.mdx
Arian Tron 61f56f997c
Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
first commit
2026-03-10 19:37:31 +03:30

156 lines
5.6 KiB
Plaintext

---
title: Cannot access Runtime data or uncached data in `generateMetadata()` or file-based Metadata in an otherwise entirely static route
---
## Why This Error Occurred
When `cacheComponents` is enabled, Next.js requires that Document Metadata not depend on uncached data or Runtime data (`cookies()`, `headers()`, `params`, `searchParams`) unless some other part of the page also has similar requirements.
Next.js determines if a page is entirely static or partially static by looking at whether any part of the page cannot be prerendered.
You control which parts of a page can be prerendered by adding `"use cache"` to components or data functions and by avoiding Runtime data like `cookies()` or `searchParams`. Metadata, though, can be defined in functions (`generateMetadata()`) far from your Page content. It can also implicitly depend on Runtime data when using file-based Metadata such as an icon inside a route with a dynamic param. This makes it easy for Metadata to accidentally make an otherwise entirely static page partially dynamic.
To prevent unwanted partially dynamic pages, Next.js expects pages that are otherwise entirely prerenderable to also have prerenderable Metadata.
## Possible Ways to Fix It
To fix this issue, you must first determine your goal for the affected route.
### Caching External Data
If your metadata does not depend on any request data, then it may be possible for you to indicate that the data is cacheable, which would allow Next.js to include it in the prerender for this route. Consider using `"use cache"` to mark the function producing the external data as cacheable.
Before:
```jsx filename="app/.../page.tsx"
import { cms } from './cms'
export async function generateMetadata() {
// This data lookup is not cached at the moment so
// Next.js will interpret this as needing to be rendered
// on every request.
const { title } = await cms.getPageData('/.../page')
return {
title,
}
}
async function getPageText() {
'use cache'
const { text } = await cms.getPageData('/.../page')
return text
}
export default async function Page() {
// This text is cached so the main content of this route
// is prerenderable.
const text = await getPageText()
return <article>{text}</article>
}
```
After:
```jsx filename="app/.../page.tsx"
import { cms } from './cms'
export async function generateMetadata() {
// By marking this function as cacheable, Next.js
// can now include it in the prerender for this route.
'use cache'
const { title } = await cms.getPageData('/.../page')
return {
title,
}
}
async function getPageText() {
'use cache'
const { text } = await cms.getPageData('/.../page')
return text
}
export default async function Page() {
// This text is cached so the main content of this route
// is prerenderable.
const text = await getPageText()
return <article>{text}</article>
}
```
### If you must access Request Data or your external data is uncacheable
If your metadata requires Request data or depends on external data that is not cacheable, Next.js will need to render this page dynamically on every request. That said, if you got this error, the rest of your page is able to be completely static. This is generally pretty rare, but if this is your actual constraint, you can indicate to Next.js that the page should be allowed to be dynamic by rendering any other component that is dynamic. Since your route doesn't have any genuine need for Request data, you can indicate an intentional dependency on a Request with `await connection()`. This is like telling Next.js that this component is never prerenderable and must be rendered on every user request.
Before:
```jsx filename="app/.../page.tsx"
import { cookies } from 'next/headers'
import { getPersonalizedTitle } from './my-api'
export async function generateMetadata() {
// In this example, we are assuming we must fetch our title
// from a protected external API. While the response is potentially
// cacheable, it still requires accessing a token from the Request cookies.
const token = (await cookies()).get('token')
const response = await getPersonalizedTitle(token)
return {
title: getTitle(response),
}
}
export default function Page() {
return <article>This article is completely static</article>
}
```
After:
```jsx filename="app/.../page.tsx"
import { Suspense } from 'react'
import { cookies } from 'next/headers'
import { connection } from 'next/server'
export async function generateMetadata() {
const token = (await cookies()).get('token')
const response = await fetch(..., { headers: { Authorization: token } })
return {
title: getTitle(response),
}
}
async function DynamicMarker() {
// This component renders nothing, but it will always
// be dynamic because it waits for an actual connection.
const Connection = async () => {
await connection()
return null
}
return (
<Suspense>
<Connection />
</Suspense>
)
}
export default function Page() {
return (
<>
<article>This article is completely static</article>
{/* Rendering this DynamicMarker component tells Next.js that
this Page has some dynamic content. */}
<DynamicMarker />
</>
)
}
```
Note: The reason to structure this `DynamicMarker` as a self-contained Suspense boundary is to avoid blocking the actual content of the page from being prerendered.
## Useful Links
- [`generateMetadata()`](/docs/app/api-reference/functions/generate-metadata)
- [`connection()`](/docs/app/api-reference/functions/connection)
- [`cookies()`](/docs/app/api-reference/functions/cookies)
- [`"use cache"`](/docs/app/api-reference/directives/use-cache)