To fetch data based on searchParams in Next.js, await the promise the page receives and pass its values into your server-side request. In the App Router, searchParams resolves to the query string values of the current URL.
Because a Server Component page can be async, the whole flow stays on the server.
// app/shop/page.tsx
export default async function Page(props: PageProps<"/shop">) {
const { query = "", sort = "asc" } = await props.searchParams;
const params = new URLSearchParams({ q: String(query), sort: String(sort) });
const res = await fetch(`https://api.example.com/products?${params}`);
const products = await res.json();
return <ul>{products.map((p) => <li key={p.id}>{p.name}</li>)}</ul>;
}Visiting the shop route with a query string such as /shop?query=shoes&sort=desc fetches products already filtered and sorted. PageProps is the generated helper that types both params and searchParams from the route path, and URLSearchParams encodes the values so a search term with a space or an ampersand cannot break the upstream URL.
Why searchParams opts the page into dynamic rendering
searchParams is a request-time API: its values are not known until the request arrives. Reading it opts the page into dynamic rendering, so the server fetches fresh data for each request instead of reusing a prerendered page.
Without Cache Components, that applies to the whole route: it is no longer prerendered, so read searchParams only when the query genuinely drives the content.
With Cache Components enabled in Next.js 16, the position of the read is what matters. Read searchParams inside a component wrapped in Suspense and the rest of the page still prerenders as a static shell, while that section streams in at request time. For the rendering implications, see static vs dynamic rendering.
Reading searchParams in a Client Component
A client page cannot be async, so it unwraps the promise with React's use function instead of await.
// app/shop/page.tsx
"use client";
import { use } from "react";
export default function Page(props: PageProps<"/shop">) {
const { query = "" } = use(props.searchParams);
return <p>Search: {query}</p>;
}The use function lets a client page read the promise without becoming async. The page still receives the value from the server, not from a second fetch. When client-side navigation changes the query string, the page re-renders with the new value.
Values are strings, not URLSearchParams
searchParams resolves to a plain object whose values are strings or arrays of strings. A repeated key such as ?tag=a&tag=b becomes an array, so the same code path must handle both a string and an array. The documented type is a record of string, string array, or undefined, which is why the first example wraps each value in String before building the query.
Defaults and missing keys
Use destructuring defaults to fill missing keys, as the example above does with query and sort. A missing query string key simply resolves to undefined, so defaults keep the fetch URL stable and prevent a request with an undefined segment.
Only pages receive searchParams
Only the page receives searchParams. A layout does not get it, because a shared layout does not re-render on every query string change and stale values would linger there.
Fetch the data in the page, then pass the result to any client component as props. Keeping the parse on the server also means one source of truth for the query values, instead of the client reading the URL again. For the difference between searchParams and the path-based params prop, see params vs searchParams.
Rune AI
Key Insights
- searchParams is a promise in current Next.js and must be awaited.
- Its values are strings or arrays of strings, not URLSearchParams.
- Reading it opts the page into dynamic rendering.
- Server Components await it; Client Components use the use function.
- Feed the parsed values straight into a server-side fetch.
Frequently Asked Questions
Is searchParams a URLSearchParams object?
Does reading searchParams affect rendering?
Can a Client Component read searchParams?
Conclusion
searchParams resolves to the query string of the current URL as a promise. Await it in a Server Component, or unwrap it with use in a client page, and pass the values into your server-side fetch.
More in this topic
`generateMetadata` Explained with Real Examples
What generateMetadata does, when it runs, and how to use it for real routes: awaited params, deduplicated data fetching, extending parent metadata, and returning a 404 from metadata.
Canonical URLs in Next.js: `metadataBase`, `alternates.canonical`, and Dynamic Pages
How canonical URLs work in the Next.js App Router: setting metadataBase once, writing alternates.canonical per route, handling dynamic segments, and what happens when the base URL is missing.
Open Graph and Twitter Card Metadata in Next.js
How to write Open Graph and Twitter card metadata in the Next.js App Router: the openGraph and twitter fields, automatic card defaults, article tags, and image merge rules.