static-route-runtime.mdx


title: Next.js encountered runtime data on a route that must be fully static kind: error

<div style={{ padding: '1.25rem 1.5rem', border: '1px solid var(--ds-gray-400)', borderRadius: '12px', background: 'var(--ds-background-200)', margin: '1.5rem 0 2rem', fontSize: '0.95rem', lineHeight: '1.6', }} > This error is part of the [Instant Navigations](https://nextjs.org/blog/next-16-3-instant-navigations) feature introduced in Next.js 16.3. If you're new to it, start with the [Ensuring instant navigations](/docs/app/guides/instant-navigation) guide. </div>

A page or layout on this route exports ensureStatic with the 'navigation' value, requiring all server-rendered work for the route to complete during prerendering.

During prerendering, the page or layout read request-specific data from cookies(), headers(), params, or searchParams. Reading these values requires rendering at request time, which conflicts with the route's static requirement.

A use cache scope also triggers this error when its expire is under five minutes, stale is under 30 seconds, or revalidate is 0.

Uncached fetch() requests, database calls, and connection() have different fixes. See Uncached data on a route that must be fully static.

Ways to fix this

<FixCardGrid> <FixCard group="remove" title="Remove the data access" href="#remove-the-data-access" snippets={[ { text: 'async function Page() {' }, { text: '- const store = await cookies()', highlight: true }, { text: ' return <Content />' }, ]} /> <FixCard group="client" title="Read the data on the client" href="#read-the-data-on-the-client" snippets={[ { text: "'use client'" }, { text: 'use(browser())', highlight: true }, { text: 'const value = readBrowserData()' }, ]} /> </FixCardGrid>

Remove the data access

Choose this fix when the content does not need to vary by request. Replace the request-specific value with a value available during prerendering.

Patterns

Remove the request-specific read

Remove the runtime API call and use a value that can be determined during prerendering.

export const ensureStatic = 'navigation'

export default function Page() {
  return <h1>My page</h1>
}

Trade-off

Every visitor receives the same value because the route no longer reads request-specific data.

Gotchas

  • This fix applies to cookies(), headers(), and other removable reads. It does not provide replacement values when the content must vary by request.

Read the data on the client

Choose this fix when the browser can read the value and the server does not need it to produce static output.

Patterns

Read URL data in a Client Component

Use useSearchParams() for the query string or useParams() for route parameters. If the hook suspends during prerendering, render the Client Component inside Suspense so the prerender can include its fallback.

'use client'

import { useSearchParams } from 'next/navigation'

export default function Query() {
  const searchParams = useSearchParams()
  return <p>Query: {searchParams.get('q')}</p>
}

Learn more: useSearchParams.

Read browser data

For data available through browser APIs, such as a non-HttpOnly cookie, call use(browser()) before reading the value. During prerendering, the component suspends and its nearest <Suspense> boundary renders a fallback.

'use client'

import { use } from 'react'
import { browser } from 'react-dom'

export default function CartCount() {
  use(browser('The cart count is stored in a cookie.'))
  const match = document.cookie.match(/(?:^|; )cart-count=(\d+)/)
  return <p>Cart ({Number(match?.[1] ?? 0)})</p>
}

Learn more: Rendering components only in the browser.

Trade-off

The prerender includes the nearest fallback. The request-specific UI appears after the browser loads and renders the Client Component.

Gotchas

  • Adding 'use client' alone does not fix this error because Client Components are also prerendered. Use a client hook that suspends or call use(browser()) before reading a browser API.
  • Do not pass the server's params or searchParams promise to the Client Component. Read URL data with the client hooks instead.
  • The browser cannot read HttpOnly cookies or arbitrary request headers. Keep sensitive data in HttpOnly cookies and choose another fix when the browser cannot access the value safely.

Other options

Extend the cache lifetime

Set expire to at least five minutes, stale to at least 30 seconds, and revalidate above 0. Increase the lifetime only when serving shared, older content is acceptable.

Learn more: cacheLife.

Verifying the fix

After applying a fix, rerun next build and confirm that the route completes prerendering. If the error also appeared in next dev, reload the route and confirm that the overlay clears. Wrapping the access in Suspense or setting instant = false does not relax this static requirement.

In next dev, the error overlay points at the failing component with file paths and line numbers. Run next build --debug-prerender for full user-frame stack traces and next build --debug-build-paths /dashboard /settings to iterate on specific routes.

Remove the static requirement

The 'navigation' value is usually set deliberately to guarantee static output for the entire server-rendered route. Removing it relaxes that requirement for every segment, not only the code that triggered this error.

If request-time rendering is intentional for this route, remove ensureStatic = 'navigation' from every page or layout that sets it. The route then follows the ordinary Cache Components rendering rules.

Learn more: Combining ensureStatic levels across layouts and pages.

See Instant Navigation validation errors for the complete reference.

Rendered from the public repository vercel/next.js on GitHub; content belongs to its authors. Cached for up to an hour.

errors/static-route-runtime.mdx · vercel/next.js | Docs MD