params VS searchParams

Used in this guide:
Next.js 15.4.3
TypeScript
Tailwind CSS

In Next.js App Router, both params and searchParams are used to access route-related data, but they serve different purposes and come from different parts of the URL:


1. params – Path Parameters (Dynamic Segments)

  • These come from dynamic route segments in the file system.
  • Example: a file like app/blog/[slug]/page.tsx means slug is a param.
  • You access params in a server component like this:

Version 1: Destructuring in the Function Signature

export default async function BlogPostPage({ params }: { params: Promise<{ slug: string }> }) {
 
    const { slug } = await params;
    
    return (
        <div>
            <h1>{slug}</h1>
        </div>
    )
}

We destructure a params property from the incoming argument. This params property is typed as a Promise that resolves to an object containing a slug property of type string.

Version 2: Explicit props Object

export default async function BlogPostPage(props: { params: Promise<{ slug: string }> }) {
 
    const { slug } = await props.params;
    
    return (
        <div>
            <h1>{slug}</h1>
        </div>
    )
}

Note:

  • params primarily used with Dynamic Route Segment ([slug], [id], etc.).

An Example of dynamic route segments in your App Router

app/
├── (main)/         
   ├── layout.tsx  
   ├── page.tsx    
   ├── favicon.ico
   └── (pages)/    
       ├── blog/
    ├── [slug]/
       ├── products/
    ├── [id]/

The value captured by that segment becomes a property in the params object that's passed to your page or layout component.

In the App Router, params is a prop directly passed to page.js and layout.js components (for server components) or accessed via the useParams() hook (for client components).




2. searchParams – Query Strings (After ?)

  • These come from the query string in the URL.
  • They are accessible in server components via the second argument of a page component:

Version 1: Destructuring in the Function Signature

export default async function Home({ searchParams }: { searchParams: Promise<{ member?: string }>}) {
 
    const member = (await searchParams).member ?? "Guest";
 
    return (
        <div>
            <p>Hi {member}</p>
        </div>
    )
}

Version 2: Explicit props Object

export default async function Home(props: { searchParams: Promise<{ member?: string }>}) {
 
    const searchParams = await props.searchParams;
    const member = searchParams.member ?? "Guest";
 
    return (
        <div>
            <p>Hi {member}</p>
        </div>
    )
}

Both examples above demonstrating different ways to handle incoming props in TypeScript with Next.js.


Differences in meanings

Version 1:

  • The destructured searchParams property is expected to be a Promise that, when resolved, yields an object which may optionally contain a member property of type string.
  • Await the searchParams Promise.
  • From the resolved value of that Promise, extract the member property.
  • Assign this member value to a new constant variable also named member. If member is null or undefined, default its value to the string 'Guest' (using the nullish coalescing operator ??)."

Version 2:

  • The props argument is expected to be an object that must contain a property named searchParams.
  • This searchParams property is a Promise that, when resolved, yields an object which may optionally contain a member property of type string.
  • Await the searchParams Promise (which is a property of the props object) and store its resolved value in a new constant called searchParams.
  • From this (resolved) searchParams object, extract the member property and store it in a constant named member. If member is null or undefined, default its value to the string 'Guest' (using the nullish coalescing operator ??)."



Key Takeaway:

The choice between destructuring in the function signature and using an explicit props object is primarily a stylistic preference in modern JavaScript/TypeScript. Both achieve the same result of making the params (or searchParams) available within your component.

Most developers using modern React and Next.js tend to favor destructuring in the function signature (({ params }) or ({ searchParams })) because it's more concise and directly indicates which properties the component is using from its incoming props.

JKT

Stay focused, and the rest will follow

©Jakkrit Turner. All rights reserved