Skip to content
API ReferenceFunctionsuseSearchParams

useSearchParams

useSearchParams is a Client Component hook that lets you read the current URL's query string.

useSearchParams returns a read-only version of the URLSearchParams interface.

app/dashboard/search-bar.tsx
'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // URL -> `/dashboard?search=my-project`
  // `search` -> 'my-project'
  return <>Search: {search}</>
}

Parameters

const searchParams = useSearchParams()

useSearchParams does not take any parameters.

Returns

useSearchParams returns a read-only version of the URLSearchParams interface, which includes utility methods for reading the URL's query string:

Good to know:

  • useSearchParams is a Client Component hook and is not supported in Server Components to prevent stale values during partial rendering.
  • If you want to fetch data in a Server Component based on search params, it's often a better option to read the searchParams prop of the corresponding Page. You can then pass it down by props to any component (Server or Client) within that Page.
  • If an application includes the /pages directory, useSearchParams will return ReadonlyURLSearchParams | null. The null value is for compatibility during migration since search params cannot be known during pre-rendering of a page that doesn't use getServerSideProps

Behavior

Static Rendering

If a route is statically rendered, calling useSearchParams will cause the Client Component tree up to the closest Suspense boundary to be client-side rendered.

This allows a part of the route to be statically rendered while the dynamic part that uses useSearchParams is client-side rendered.

We recommend wrapping the Client Component that uses useSearchParams in a <Suspense/> boundary. This will allow any Client Components above it to be statically rendered and sent as part of initial HTML. Example.

For example:

app/dashboard/search-bar.tsx
'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // This will not be logged on the server when using static rendering
  console.log(search)
 
  return <>Search: {search}</>
}
app/dashboard/page.tsx
import { Suspense } from 'react'
import SearchBar from './search-bar'
 
// This component passed as a fallback to the Suspense boundary
// will be rendered in place of the search bar in the initial HTML.
// When the value is available during React hydration the fallback
// will be replaced with the `<SearchBar>` component.
function SearchBarFallback() {
  return <>placeholder</>
}
 
export default function Page() {
  return (
    <>
      <nav>
        <Suspense fallback={<SearchBarFallback />}>
          <SearchBar />
        </Suspense>
      </nav>
      <h1>Dashboard</h1>
    </>
  )
}

Good to know:

  • In development, routes are rendered on-demand, so useSearchParams doesn't suspend and things may appear to work without Suspense.
  • During production builds, a static page that calls useSearchParams from a Client Component must be wrapped in a Suspense boundary, otherwise the build fails with the Missing Suspense boundary with useSearchParams error.
  • If you intend the route to be dynamically rendered, prefer using the connection function first in a Server Component to wait for an incoming request, this excludes everything below from prerendering. See what makes a route dynamic in the Dynamic Rendering guide.
  • If you're already in a Server Component Page, consider using the searchParams prop and passing the values to Client Components.
  • You can also pass the Page searchParams prop directly to a Client Component and unwrap it with React's use(). Although this will suspend, so the Client Component should be wrapped with a Suspense boundary.

Dynamic Rendering

If a route is dynamically rendered, useSearchParams will be available on the server during the initial server render of the Client Component.

For example:

app/dashboard/search-bar.tsx
'use client'
 
import { useSearchParams } from 'next/navigation'
 
export default function SearchBar() {
  const searchParams = useSearchParams()
 
  const search = searchParams.get('search')
 
  // This will be logged on the server during the initial render
  // and on the client on subsequent navigations.
  console.log(search)
 
  return <>Search: {search}</>
}
app/dashboard/page.tsx
import { connection } from 'next/server'
import SearchBar from './search-bar'
 
export default async function Page() {
  await connection()
  return (
    <>
      <nav>
        <SearchBar />
      </nav>
      <h1>Dashboard</h1>
    </>
  )
}

Good to know:

  • Previously, setting export const dynamic = 'force-dynamic' on the page was used to force dynamic rendering. Prefer using connection() instead, as it semantically ties dynamic rendering to the incoming request.

Server Components

Pages

To access search params in Pages (Server Components), use the searchParams prop.

Layouts

Unlike Pages, Layouts (Server Components) do not receive the searchParams prop. This is because a shared layout is not re-rendered during navigation which could lead to stale searchParams between navigations. View detailed explanation.

Instead, use the Page searchParams prop or the useSearchParams hook in a Client Component, which is re-rendered on the client with the latest searchParams.

Examples

Updating searchParams

You can use useRouter or Link to set new searchParams. After a navigation is performed, the current page.js will receive an updated searchParams prop.

app/example-client-component.tsx
'use client'
 
export default function ExampleClientComponent() {
  const router = useRouter()
  const pathname = usePathname()
  const searchParams = useSearchParams()
 
  // Get a new searchParams string by merging the current
  // searchParams with a provided key/value pair
  const createQueryString = useCallback(
    (name: string, value: string) => {
      const params = new URLSearchParams(searchParams.toString())
      params.set(name, value)
 
      return params.toString()
    },
    [searchParams]
  )
 
  return (
    <>
      <p>Sort By</p>
 
      {/* using useRouter */}
      <button
        onClick={() => {
          // <pathname>?sort=asc
          router.push(pathname + '?' + createQueryString('sort', 'asc'))
        }}
      >
        ASC
      </button>
 
      {/* using <Link> */}
      <Link
        href={
          // <pathname>?sort=desc
          pathname + '?' + createQueryString('sort', 'desc')
        }
      >
        DESC
      </Link>
    </>
  )
}

Version History

VersionChanges
v13.0.0useSearchParams introduced.