Back to Next Js

Client navigation hook requires a Suspense boundary

errors/next-prerender-client-hook.mdx

16.3.03.4 KB
Original Source

Why This Error Occurred

When cacheComponents is enabled, Next.js prerenders as much of a route as possible before a request arrives. A Client Component used a navigation hook whose value was not available during that prerender, but the component was not inside a Suspense boundary.

This can happen with the following hooks:

These hooks are reactive during client navigation. If their initial value is not known while prerendering, Next.js needs a fallback to include in the static shell until the runtime value is available.

Possible Ways to Fix It

Wrap the Client Component in Suspense

Wrap the smallest subtree that uses the hook in a Suspense boundary. Next.js can then prerender the fallback and replace it with the Client Component when the runtime value is available.

Before:

jsx
import { Search } from './search'

export default function Page() {
  return (
    <main>
      <h1>Dashboard</h1>
      <Search />
    </main>
  )
}
jsx
'use client'

import { useSearchParams } from 'next/navigation'

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

After:

jsx
import { Suspense } from 'react'
import { Search } from './search'

export default function Page() {
  return (
    <main>
      <h1>Dashboard</h1>
      <Suspense fallback={<p>Loading search...</p>}>
        <Search />
      </Suspense>
    </main>
  )
}

The fallback should be synchronous and deterministic. Place the boundary close to the component that uses the hook so the rest of the route can remain in the prerendered shell.

Prerender Known Dynamic Params

For hooks that derive their value from dynamic route params, use generateStaticParams when the possible values are known ahead of time:

jsx
export function generateStaticParams() {
  return [{ slug: 'hello-world' }, { slug: 'release-notes' }]
}

export default function Page() {
  return <BlogNavigation />
}

For the generated paths, useParams, usePathname, and the selected-layout-segment hooks can resolve during prerendering. Paths not returned by generateStaticParams may still require a Suspense boundary.

generateStaticParams does not provide search parameters. Components that use useSearchParams should be wrapped in Suspense when the route is prerendered.