`page.js` in the Next.js App Router: Props, Params, and Search Params

The page file is what makes a route public in the App Router. Learn what props it receives and how to read params and searchParams correctly.

7 min read

A Next.js page.js file, usually written as page.tsx in a TypeScript project, is the file that makes a route segment public in the App Router. It default-exports a component, and that component can receive two special props: params for dynamic path segments, and searchParams for the query string.

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

Visiting /blog/hello-world renders "Post: hello-world". The bracketed folder name in the file path is what tells Next.js to capture that URL segment and hand it to the page as a prop.

Reading params

The params prop resolves to an object built from every dynamic segment in the route, from the root down to this page. Since Next.js 15 it is a promise, so a page component that reads it needs to be async and use await.

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

Requesting shop, shoes, nike-air resolves category to "shoes" and item to "nike-air". A static route with no bracketed folders still receives this prop, but it resolves to an empty object.

Reading searchParams

The searchParams prop resolves to a plain object built from the query string of the current URL. It is also a promise, and reading it opts the page into request-time rendering, because query values cannot be known ahead of a real request.

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

Visiting the shop page with a sort query set to desc renders "Sorted: desc". Leaving off the query string falls back to "Sorted: asc" because of the default value in the destructure.

Reading them in a Client Component page

A page marked with the client directive cannot be async, so it cannot await these props directly. Use React's use function to unwrap the promise instead.

App.tsxApp.tsx
// app/blog/[slug]/page.tsx
"use client";
import { use } from "react";
 
type Params = Promise<{ slug: string }>;
 
export default function Page({ params }: { params: Params }) {
  const { slug } = use(params);
  return <h1>Post: {slug}</h1>;
}

This component runs in the browser, which is why the directive sits at the top of the file: something on the page needs client-side interactivity, and the use function is what lets it still read a promise-based prop without becoming an async component.

params and searchParams at a glance

PropSourceAvailable in
paramsDynamic segments in the folder pathPage, layout, route handler
searchParamsQuery string after the question markPage only

Layouts never receive the search params prop, because a shared layout does not re-render on every navigation and stale query values would linger there. For the layout and page split in more depth, see layouts in Next.js. For a direct side-by-side comparison of the two props, see params vs searchParams.

Common mistake

Reading a value straight off params without await or use throws a runtime error in current Next.js versions. Both props changed from plain objects to promises, so any code copied from an older tutorial needs that one adjustment before it will run.

Rune AI

Rune AI

Key Insights

  • page.tsx is the file that makes a route segment publicly reachable.
  • Pages are Server Components by default and can be async.
  • params holds the dynamic segment values from the URL path.
  • searchParams holds the query string values after the question mark.
  • Both props are promises in current Next.js and must be awaited or unwrapped with use.
RunePowered by Rune AI

Frequently Asked Questions

Are params and searchParams available in a layout too?

A layout receives params, but not searchParams. Reading searchParams in a layout would make every page under it re-render together, so Next.js keeps it on the page instead.

Why do I have to await params instead of reading it directly?

Since Next.js 15, params and searchParams are promises so the framework can start rendering a route's static shell before the request-specific values are known. Awaiting them is what lets that part of the page stream in.

Can a Client Component page read searchParams directly?

A Client Component page still receives searchParams as a promise, so it must unwrap it with React's use function instead of async/await, since a component marked with use client cannot be an async function.

Conclusion

A page file is the file that makes a route segment public, and it can receive both params and searchParams as promises. Awaiting them is what gives Next.js room to render the parts of a page that do not depend on the request.