---
title: Next.js encountered runtime data on a route that must be fully static
url: "https://nextjs.org/docs/messages/static-route-runtime"
docs_index: /docs/llms.txt
---



<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`](/docs/app/api-reference/file-conventions/route-segment-config/ensureStatic) with the `'navigation'` value, requiring all server-rendered work for the route to complete during prerendering.

During [prerendering](/docs/app/glossary#prerendering), the page or layout read request-specific data from [`cookies()`](/docs/app/api-reference/functions/cookies), [`headers()`](/docs/app/api-reference/functions/headers), [`params`](/docs/app/api-reference/file-conventions/page#params-optional), or [`searchParams`](/docs/app/api-reference/file-conventions/page#searchparams-optional). Reading these values requires rendering at request time, which conflicts with the route's static requirement.

A [`use cache`](/docs/app/api-reference/directives/use-cache) scope also triggers this error when its [`expire`](/docs/app/api-reference/functions/cacheLife#expire) is under five minutes, [`stale`](/docs/app/api-reference/functions/cacheLife#stale) is under 30 seconds, or [`revalidate`](/docs/app/api-reference/functions/cacheLife#revalidate) is `0`.

Uncached [`fetch()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch) requests, database calls, and [`connection()`](/docs/app/api-reference/functions/connection) have different fixes. See [Uncached data on a route that must be fully static](/docs/messages/static-route-dynamic).

## 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.

```jsx filename="app/page.jsx"
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()`](/docs/app/api-reference/functions/use-search-params) for the query string or [`useParams()`](/docs/app/api-reference/functions/use-params) for route parameters. If the hook suspends during prerendering, render the Client Component inside [`Suspense`](https://react.dev/reference/react/Suspense) so the prerender can include its fallback.

```jsx filename="app/search/query.jsx"
'use client'

import { useSearchParams } from 'next/navigation'

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

Learn more: [`useSearchParams`](/docs/app/api-reference/functions/use-search-params).

#### Read browser data

For data available through browser APIs, such as a non-`HttpOnly` cookie, call [`use(browser())`](/docs/app/guides/single-page-applications#rendering-components-only-in-the-browser) before reading the value. During prerendering, the component suspends and its nearest `<Suspense>` boundary renders a fallback.

```jsx filename="app/cart-count.jsx"
'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](/docs/app/guides/single-page-applications#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`](/docs/app/api-reference/functions/cacheLife).

## Verifying the fix

After applying a fix, rerun [`next build`](/docs/app/api-reference/cli/next#next-build-options) and confirm that the route completes prerendering. If the error also appeared in [`next dev`](/docs/app/api-reference/cli/next#next-dev-options), 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`](/docs/app/guides/building#debug-prerender-errors) 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](/docs/app/getting-started/caching) rendering rules.

Learn more: [Combining `ensureStatic` levels across layouts and pages](/docs/app/api-reference/file-conventions/route-segment-config/ensureStatic#combining-levels-across-layouts-and-pages).

## Related validation errors

See [Instant Navigation validation errors](/docs/messages/instant-navigation-validation) for the complete reference.
