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/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/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/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/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
| Prop | Source | Available in |
|---|---|---|
| params | Dynamic segments in the folder path | Page, layout, route handler |
| searchParams | Query string after the question mark | Page 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
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.
Frequently Asked Questions
Are params and searchParams available in a layout too?
Why do I have to await params instead of reading it directly?
Can a Client Component page read searchParams directly?
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.
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.