How to fix useSearchParams only works in Client Components in React
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>;
}- Add "use client" directive to the component
- Use searchParams prop in Server Components instead
- Wrap Client Component in Suspense boundary for static routes
- Extract Client Component logic into a separate file
'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
- 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)
- Attempting to access URL search parameters using the hook pattern instead of the searchParams prop in Server Components
- Converting a Client Component to a Server Component without replacing useSearchParams with the searchParams prop
- Placing useSearchParams in a shared component that gets imported by both Server and Client Components
- Missing "use client" directive at the top of a file that uses useSearchParams
- Using useSearchParams in a statically exported route without proper Suspense boundaries
How to fix "useSearchParams only works in Client Components"
The simplest fix is to mark your component as a Client Component by adding the "use client" directive at the top of the file:
'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.
If you're in a Page component (Server Component), use the searchParams prop instead of the hook:
// 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.
If you're using useSearchParams in a statically rendered route, wrap the component in a Suspense boundary:
// 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.
If you have a mixed component, split the search params logic into its own Client Component:
// 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.
For better server-side rendering, read params in the Server Component and pass them as props:
// 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.
If you intend the route to be fully dynamic, use the connection function in the Server Component:
// 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.
After implementing your fix, run a production build to ensure there are no Suspense boundary errors:
npm run buildCheck 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
- ๐React Official Documentation
- ๐Next.js: useSearchParams Function Reference(Official Docs)
- ๐Next.js: Missing Suspense Boundary Error(Official Docs)
- ๐
- ๐
- ๐