Next.js `params` vs `searchParams`: How to Read URL Parameters

params and searchParams both come from the URL but capture different parts of it. Learn the difference and how to read each one correctly.

6 min read

Next.js params and searchParams both describe the current URL, but they capture two different parts of it. The params prop holds values from the folder path itself, while the searchParams prop holds values from the query string after the question mark.

texttext
/products/running-shoes?sort=price&order=asc
          ------------- ---------------------
          params.slug    searchParams

For a route file at app/products/[slug]/page.tsx, this single URL fills params with the product slug and searchParams with the sort options. Neither prop overlaps with the other.

Where params comes from

A page only receives params when its route has a bracketed folder somewhere in the path. The value comes entirely from the URL's path segments, not from anything after the question mark.

App.tsxApp.tsx
// app/products/[slug]/page.tsx
export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  return <h1>{slug}</h1>;
}

Visiting /products/running-shoes resolves slug to "running-shoes", regardless of any query string appended to the same URL.

Where searchParams comes from

The searchParams prop holds everything after the question mark, parsed into a plain object. It exists on every page, even one with no dynamic segments in its path at all.

App.tsxApp.tsx
// app/products/[slug]/page.tsx
export default async function Page({
  searchParams,
}: {
  searchParams: Promise<{ sort?: string }>;
}) {
  const { sort } = await searchParams;
  return <p>Sort: {sort ?? "default"}</p>;
}

Requesting the running shoes page with a sort value of price renders "Sort: price". Leaving off the query string renders "Sort: default" because of the nullish fallback.

Side by side

paramssearchParams
Comes fromFolder path segmentsQuery string after ?
Needs a dynamic segmentYesNo
Available in layoutsYesNo
Value typeString or array of stringsPlain object of strings

Both are request-dependent data, so a layout never receives searchParams even though it can receive params. That rule is covered in more depth in page.js props, params, and search params.

Reading both together

A page can accept both props at once, which is common on a product listing that is both dynamic and filterable.

App.tsxApp.tsx
// app/products/[slug]/page.tsx
type Props = {
  params: Promise<{ slug: string }>;
  searchParams: Promise<{ sort?: string }>;
};
 
export default async function Page({ params, searchParams }: Props) {
  const { slug } = await params;
  const { sort } = await searchParams;
  return <p>{slug} sorted by {sort ?? "default"}</p>;
}

Awaiting each prop separately keeps the two sources of data clearly labeled in the code, which matters once a page reads several dynamic segments alongside several query values. For the fully worked-out dynamic segment example on its own, see dynamic routes in Next.js.

Common mistake

Mixing up the two names is the most common mistake, especially when a route has both a dynamic segment and query filters. If a value is missing where you expect it, check whether it actually lives in the path or in the query string, since reading the wrong prop returns undefined instead of an error.

A second mistake is reaching for params when the value should really change without a page reload, such as a sort order a visitor toggles repeatedly. Because params comes from the folder structure, changing it means navigating to a different URL entirely, while a searchParams value can update in place through a link or a router call. Choosing the wrong one early tends to force a larger rewrite later, so decide up front whether a value identifies a resource or merely adjusts how it is displayed.

Rune AI

Rune AI

Key Insights

  • params comes from dynamic segments defined by folder names in the route.
  • searchParams comes from the query string that follows the question mark in a URL.
  • Both are promises on the page prop and must be awaited or unwrapped with use.
  • Only pages receive searchParams; layouts only receive params.
  • The useSearchParams hook is the Client Component alternative to the page prop.
RunePowered by Rune AI

Frequently Asked Questions

Can a page use params and searchParams at the same time?

Yes. A page can accept both props together, for example a dynamic product page that also reads a query string for sorting or filtering options.

Why does reading searchParams make a page dynamic?

Query string values are only known once a real request arrives with a specific URL, so a page that reads them cannot be fully prerendered ahead of time without a Suspense boundary around that part of the tree.

Is searchParams a URLSearchParams instance?

No. The searchParams prop on a page is a plain JavaScript object, not a URLSearchParams instance. The useSearchParams hook in a Client Component returns a real URLSearchParams instance instead.

Conclusion

params captures values from the folder structure of the path, and searchParams captures the query string after the question mark. Reach for params to identify a resource and searchParams to filter, sort, or paginate it.