Next.jsReact

useSearchParams() needs a Suspense boundary

useSearchParams() should be wrapped in a suspense boundary at page "/search"

In short: A Client Component called useSearchParams() during render without a parent <Suspense> boundary, so Next.js couldn't finish a static render of the page.

Why it happens

useSearchParams() reads the URL query string, which isn't known at build time. If Next.js rendered that component as part of a statically generated page, the output could be wrong. The framework requires a <Suspense> boundary around the component that calls it, so the rest of the page can still be static and the query-string part can resolve on the client. AI-generated pages often call useSearchParams() directly in a page or layout with no boundary.

How to fix it

  1. Move the useSearchParams() call into a small Client Component, not the whole page or layout.
  2. In the parent Server Component (the page), wrap that child in <Suspense fallback={...}> with a short loading state.
  3. Keep the rest of the page (headings, data fetched on the server) outside the boundary so it can still render statically.
  4. If you only need a query param in a click handler or useEffect, you can read it there and avoid blocking render, but the Suspense rule still applies if the hook runs during render.
  5. Rebuild and open the page with and without query params to confirm the fallback appears briefly and the content matches the URL.

Example

"use client";
import { useSearchParams } from "next/navigation";

export function Filters() {
  const params = useSearchParams();
  const q = params.get("q") ?? "";
  return <p>Search: {q || "(none)"}</p>;
}

// app/search/page.tsx (Server Component)
import { Suspense } from "react";
import { Filters } from "./filters";

export default function SearchPage() {
  return (
    <>
      <h1>Search</h1>
      <Suspense fallback={<p>Loading filters…</p>}>
        <Filters />
      </Suspense>
    </>
  );
}
Don't: Don't wrap your root layout in Suspense with an empty fallback just to silence the warning. That hides the whole page and doesn't fix a hook called from the layout itself.

Copy-paste fix prompt

3 · The fix promptPaste into Cursor, Claude Code, Codex, Lovable, Bolt, Replit or v0
I'm getting this error in my app:

useSearchParams() should be wrapped in a suspense boundary at page "/search"

[Paste the full error, stack trace, and the file it points to here]

Likely cause: A Client Component called useSearchParams() during render without a parent <Suspense> boundary, so Next.js couldn't finish a static render of the page.

Task: Find every useSearchParams() call, move each one into a small Client Component, and wrap that component in Suspense from the parent Server Component. Don't add Suspense around the root layout to hide the warning.

Rules:
- First explain the root cause in 2 sentences and list the files you'll change.
- Make the smallest change that fixes it. Don't refactor unrelated code.
- Don't disable security or checks (RLS, auth, signature verification, type checking, CORS allow-all) to make the error disappear.
- Never print or hard-code secret keys.
- Finish by telling me exactly how to verify the fix.

Common with: Cursor, v0, Claude Code. Last reviewed 2026-11-15.

Related fixes

← All fixes · Still stuck? Use the diagnose-first prompt