errors/next-prerender-client-hook.mdx
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:
useSearchParams, because the query string comes from the request URLuseParams, usePathname, useSelectedLayoutSegment, or useSelectedLayoutSegments when the route contains dynamic params that were not provided by generateStaticParamsThese 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.
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:
import { Search } from './search'
export default function Page() {
return (
<main>
<h1>Dashboard</h1>
<Search />
</main>
)
}
'use client'
import { useSearchParams } from 'next/navigation'
export function Search() {
const searchParams = useSearchParams()
return <p>Search: {searchParams.get('q')}</p>
}
After:
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.
For hooks that derive their value from dynamic route params, use generateStaticParams when the possible values are known ahead of time:
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.