How to fix useSearchParams only works in Client Components in React

ReactINTERMEDIATEMEDIUMUpdated Dec 8, 2025ยท 97 views

This error occurs when trying to use the useSearchParams hook in a Next.js Server Component. The hook is designed exclusively for Client Components to prevent stale values during partial rendering and maintain proper hydration.

Quick fix

Fixes useSearchParams only works in Client Components

'use client';

import { useSearchParams } from 'next/navigation';

export default function SearchComponent() {
  const searchParams = useSearchParams();
  const query = searchParams.get('q');

  return <div>Search: {query}</div>;
}
  1. Add "use client" directive to the component
  2. Use searchParams prop in Server Components instead
  3. Wrap Client Component in Suspense boundary for static routes
  4. Extract Client Component logic into a separate file
react โ€” error
'use client';
import { useSearchParams } from 'next/navigation';
export default function SearchComponent() {
const searchParams = useSearchParams();
const query = searchParams.get('q');
return <div>Search: {query}</div>;
}
useSearchParams only works in Client Components

What this error means

The useSearchParams hook is a Client Component-only feature in Next.js that provides access to the current URL's query string parameters. When you attempt to use this hook in a Server Component, Next.js throws this error to prevent architectural violations. This restriction exists because Server Components render on the server and cannot access browser-specific APIs or maintain reactive state tied to URL changes. The useSearchParams hook needs to react to URL changes in real-time, which requires client-side JavaScript execution. Using it in Server Components would lead to stale values during partial rendering and break Next.js's rendering model. Next.js provides alternative approaches for accessing search parameters in Server Components, primarily through the searchParams prop available in Page components. This ensures proper server-side rendering while maintaining type safety and preventing hydration mismatches.

Typical symptoms

  • Build fails with error message "useSearchParams only works in Client Components"
  • TypeScript or runtime error when calling useSearchParams() in a .tsx file without "use client" directive
  • Production build fails with "Missing Suspense boundary with useSearchParams" error
  • Page that was working in development fails during production build
  • Client Component tree unexpectedly rendering client-side instead of being statically generated
  • Components above useSearchParams usage becoming dynamically rendered when they should be static
  • Hydration errors when mixing Server and Client Component search param access patterns

Common causes

  1. Using useSearchParams() in a Server Component (file without "use client" directive)
  2. Importing and calling useSearchParams in a page.tsx or layout.tsx Server Component
  3. Using useSearchParams in a Client Component without wrapping it in a Suspense boundary (in static routes)
  4. Attempting to access URL search parameters using the hook pattern instead of the searchParams prop in Server Components
  5. Converting a Client Component to a Server Component without replacing useSearchParams with the searchParams prop
  6. Placing useSearchParams in a shared component that gets imported by both Server and Client Components
  7. Missing "use client" directive at the top of a file that uses useSearchParams
  8. Using useSearchParams in a statically exported route without proper Suspense boundaries

How to fix "useSearchParams only works in Client Components"

1Add "use client" directive to the component

The simplest fix is to mark your component as a Client Component by adding the "use client" directive at the top of the file:

tsx
'use client';

import { useSearchParams } from 'next/navigation';

export default function SearchComponent() {
  const searchParams = useSearchParams();
  const query = searchParams.get('q');

  return <div>Search: {query}</div>;
}

This tells Next.js that this component and its imports should run on the client, allowing access to useSearchParams.

2Use searchParams prop in Server Components instead

If you're in a Page component (Server Component), use the searchParams prop instead of the hook:

tsx
// app/search/page.tsx
export default function SearchPage({
  searchParams,
}: {
  searchParams: { q?: string }
}) {
  const query = searchParams.q;

  return <div>Search: {query}</div>;
}

This approach works in Server Components and enables proper server-side rendering. You can then pass these values down to Client Components as props if needed.

3Wrap Client Component in Suspense boundary for static routes

If you're using useSearchParams in a statically rendered route, wrap the component in a Suspense boundary:

tsx
// app/page.tsx
import { Suspense } from 'react';
import SearchComponent from '@/components/SearchComponent';

export default function Page() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <SearchComponent />
    </Suspense>
  );
}

This allows Next.js to statically render everything above the Suspense boundary while client-rendering the dynamic search params component.

4Extract Client Component logic into a separate file

If you have a mixed component, split the search params logic into its own Client Component:

tsx
// components/SearchFilter.tsx
'use client';

import { useSearchParams } from 'next/navigation';

export function SearchFilter() {
  const searchParams = useSearchParams();
  const filter = searchParams.get('filter');

  return <div>Filter: {filter}</div>;
}

// app/products/page.tsx (Server Component)
import { SearchFilter } from '@/components/SearchFilter';

export default function ProductsPage() {
  return (
    <div>
      <h1>Products</h1>
      <SearchFilter />
    </div>
  );
}

This maintains the benefits of Server Components while isolating client-side search param access.

5Pass search params from Server to Client Components

For better server-side rendering, read params in the Server Component and pass them as props:

tsx
// app/search/page.tsx (Server Component)
import { SearchResults } from '@/components/SearchResults';

export default function SearchPage({
  searchParams,
}: {
  searchParams: { q?: string; page?: string }
}) {
  return (
    <SearchResults
      query={searchParams.q}
      page={searchParams.page}
    />
  );
}

// components/SearchResults.tsx (Client Component)
'use client';

interface SearchResultsProps {
  query?: string;
  page?: string;
}

export function SearchResults({ query, page }: SearchResultsProps) {
  // Use the props instead of useSearchParams
  return <div>Searching for: {query}, Page: {page}</div>;
}

This pattern provides better performance and SEO while maintaining full functionality.

6Use connection() for dynamic rendering in Server Components

If you intend the route to be fully dynamic, use the connection function in the Server Component:

tsx
// app/search/page.tsx
import { connection } from 'next/server';

export default async function SearchPage({
  searchParams,
}: {
  searchParams: { q?: string }
}) {
  await connection(); // Wait for incoming request

  const query = searchParams.q;
  return <div>Dynamic search: {query}</div>;
}

This opts the entire route into dynamic rendering, preventing static generation issues.

7Verify build success after changes

After implementing your fix, run a production build to ensure there are no Suspense boundary errors:

bash
npm run build

Check the build output for any warnings about missing Suspense boundaries or static/dynamic rendering. A successful build confirms your search params implementation is correct.

Advanced notes

Static vs Dynamic Rendering Impact: When useSearchParams is called in a Client Component within a statically rendered route, Next.js will client-side render the entire component tree up to the nearest Suspense boundary. This can impact your page's performance and SEO if not properly managed. Always wrap useSearchParams components in Suspense boundaries on static routes.

Layout Components Limitation: Unlike Page components, Layout components do not receive the searchParams prop. If you need search params in a layout, you must either use a Client Component with useSearchParams or pass the params down from the page component.

TypeScript Type Safety: When using the searchParams prop, define proper TypeScript types to catch missing or incorrectly named parameters at compile time. This prevents runtime errors from URL parameter mismatches.

Router Cache Behavior: The useSearchParams hook returns a ReadonlyURLSearchParams object with methods like get(), getAll(), has(), and toString(). These methods are optimized for Next.js's router cache and will trigger re-renders when search params change.

Migration from Pages Router: If you're migrating from Next.js Pages Router where useRouter().query was used everywhere, note that the App Router separates concerns: use searchParams prop in Server Components (pages) and useSearchParams hook in Client Components. This separation improves performance and enables better static optimization.

Debugging Build Errors: If you encounter "Missing Suspense boundary" errors during build but not development, it's because Next.js only enforces this requirement in production builds for static optimization. Always test with 'npm run build' before deploying.

Frequently asked questions

What does "useSearchParams only works in Client Components" mean?
js that provides access to the current URL's query string parameters. js throws this error to prevent architectural violations. This restriction exists because Server Components render on the server and cannot access browser-specific APIs or maintain reactive state tied to URL changes.
How do I fix "useSearchParams only works in Client Components"?
This error occurs when trying to use the useSearchParams hook in a Next.js Server Component. The hook is designed exclusively for Client Components to prevent stale values during partial rendering and maintain proper hydration.
What causes "useSearchParams only works in Client Components"?
Using useSearchParams() in a Server Component (file without "use client" directive) Importing and calling useSearchParams in a page.tsx or layout.tsx Server Component Using useSearchParams in a Client Component without wrapping it in a Suspense boundary (in static routes)
Is the "useSearchParams only works in Client Components" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading