本文へ移動
verified onnext@16.3.5react@19
最終検証日 2026-09-26
Next.js道場

useSearchParams を Suspense で囲まないと止まる

実際に出るエラー

useSearchParams() should be wrapped in a suspense boundary at page "/find".
Read more: https://nextjs.org/docs/messages/missing-suspense-with-csr-bailout
Error occurred prerendering page "/find".
Export encountered an error on /find/page: /find, exiting the build.

useSearchParams を Suspense で囲まずに使ったときに出るビルドエラーです。

何が決まっていないのか

'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function Find() {
  const q = useSearchParams().get('q')
  return <p>{q}</p>
}
useSearchParams() should be wrapped in a suspense boundary at page "/find".

use client を付けてあるのに止まります。ここが分かりにくいところです。

use client を付けても、ビルド時に一度は HTML を作ります。そのとき ?q=... に何が入るかは決まっていません。何を描けばよいか決まらないので、そこで止まります。

直し方は囲うこと。設定ではない

読む部分だけを切り出して Suspense で囲みます。

import { Suspense } from 'react'
import { SearchBox } from './SearchBox'
 
export default function Find() {
  return (
    <Suspense fallback={<p>読み込み中です</p>}>
      <SearchBox />
    </Suspense>
  )
}

実機で確かめました。これでビルドは通り、しかもページは事前に描かれたまま残ります。

Route (app)
└ ○ /find        ← 静的のまま

出来あがった HTML には 読み込み中です が入っていました。ブラウザに届いたあと、URL を読んで中身が置き換わります。

似ているが結論が逆の話

「Suspense で囲めば静的なまま」は、いつでも成り立つわけではありません。

どちらも実機で確かめた。仕組みが違うので結論も違う
囲った中で読むもの読む場所外側
useSearchParamsブラウザ静的のまま
cookies()サーバールート全体が動的になる

cookies() はサーバーが要求を受け取って初めて読めます。だから1か所でも読むと、ルート全体がアクセスのたびに描かれる側へ移ります(この問題で実機の結果を出しています)。

useSearchParams はブラウザに届いたあとに読みます。サーバーは何も待たなくてよいので、外側は事前に描けます。

実際に動いているもの

このサイトの検索の最小構成は、この形で動いています。説明用に書き直したコードではなく、そのページを動かしている本物のファイルです。

出る条件をまとめると

  1. useSearchParams を使っている
  2. そのページが事前に描かれる対象になっている
  3. 読む部分が Suspense で囲まれていない

3つ揃ったときだけ出ます。直すのは3つめです。

出典

このページの内容は上記の一次情報を基準に書いています。個人ブログや二次情報を根拠にしていません。

理解できたか試す

では、このコードはどうなりますか。

検索語を読むだけの小さな部品です。ページに置いたらビルドが失敗しました。原因はどれですか。

この問題を解くこのテーマの問題 3 問