43

I'm encountering an issue when trying to use asynchronous parameters in a Next.js 15 app. I want to extract the slug parameter from params, which is returned as a Promise.

Here's my current setup in page.tsx:

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params: tParams }) {
  const { slug } = await params;
  const productID = slug[1];

  // my code here
}

When I run npm run build, I get this error:

Type error: Type '{ params: { id: string; }; }' does not satisfy the constraint 'PageProps'. Types of property 'params' are incompatible. Type '{ id: string; }' is missing the following properties from type 'Promise': then, catch, finally, [Symbol.toStringTag]

It seems like the type for params is causing issues, possibly because Next.js expects a different structure for params.

What I’ve Tried

  • I initially defined params as { slug: string[] }, but I changed it to Promise<{ slug: string[] }> to try to handle the async behavior.
  • I also tried different configurations for the params type without success.

Question

How can I correctly type the params object for asynchronous access in Next.js 15, or is there a better approach for handling this?

2

17 Answers 17

46

I fixed the issue by doing this

without async await


import { use } from "react";
    
export default function CategoryDetail({params}: {params: Promise<{ id: string }>}) {
const { id } = use(params);
...

with async await

    
export default async function CategoryDetail({params}: {params: Promise<{ id: string }>}) {
const { id } = await params;
...
Sign up to request clarification or add additional context in comments.

2 Comments

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
Дякую це мені дуже допомогло) цілий день парилась над цією проблеиою!!!!
28

From the example in the migration guide they show that you can't use the destructured members of an asynchronous page props...

Maybe try this change -

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge(props: { params: tParams }) {
  const { slug } = await props.params;
  const productID = slug[1];

  // other code here
}

Comments

9

In nextJS 15 params is a promise and you have to await it,you also have to be specific destructuring your params You can solve this issues in two ways, using async await. or by importing use from 'react' on a client component.

Using Async Await

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params:  tParams }) {
  const { slug }: {slug: string[]} = await params; // fix this line
  const productID = slug[1];

  // other code here
}

using import from react

 import use from 'react' // import this line

type tParams = Promise<{ slug: string[] }>;

export default function Challenge({ params }: { params:  tParams }) {
  const { slug }: {slug: string[]} = use(params) ; // fix this line
  const productID = slug[1];

  // other code here
}

Comments

4

install this npx @next/codemod@latest next-async-request-api .

type tParams = Promise<{ slug: string[] }>;

export default async function Challenge({ params }: { params: tParams }) {
  const { slug } = await params;
  const productID = slug[1];
}

just install it you did correct

1 Comment

Could you add a document linked to it
3

Nextjs 15 dynamic rendering works with this pattern

export default async function PostPage(params: { 
 params: Promise<{ slug: string }>;) {
  const slug = await(params).slug;
  return <Block slug={slug}/>
}

1 Comment

2

There is documentation about Asynchronous Page in the Next.js:

https://nextjs.org/docs/app/building-your-application/upgrading/version-15#asynchronous-page

Try that approach, which is in the Next.js documentation:

export default async function Challenge(
 props: {
  params: Promise<{ slug: string }>;
 }
) {
 const params = await props.params;
 const productID = params.slug[1];
 // const productID = params.slug;
 // other code here
}

Comments

2

Here’s how I fix this issue:

Previously it looked like this:

export default async function Page({
  params,
}: {
  params: { slug: string };
}) {
  const slug = params.slug;
  const response = await getProjectBySlug(slug);

Then, I changed it to:

export default async function Page(props: {
  params: Promise<{ slug: string }>;
}) {
  const params = await props.params;
  const response = await getProjectBySlug(params.slug);

Comments

2

Failing code -->

export default function Page({
  params,
}: {
  params: { slug: string };
}) {
  const pageData = vslConfig.pages[params.slug as keyof typeof vslConfig.pages];

Working Code --

interface PageProps {
  params: Promise<{ slug: string }>;
}

export default async function Page(props: PageProps) {
  const { slug } = await props.params;
  const pageData = vslConfig.pages[slug as keyof typeof vslConfig.pages];

Comments

1

based on nextjs15 docs, you can do this:

export default async function Page({
  params,
}: {
  params: Promise<{ slug: string }>
}) {
  const slug = (await params).slug
  return <div>My Post: {slug}</div>
}

Comments

1

Do not destructure slug again, I used this format and it worked fine,

const Page = async ({ params }: { params: Promise<{ id: string }> }) => {

const id = (await params).id;

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
1

install npx @next/codemod@canary next-async-request-api . and then const BlogPage = async ({ params }: { params: Promise<{ id: string }> }) => { const { id } = await params; const blog = blogs.find((blog) => blog.id === id); return JSX };

Comments

0
type tParams = { slug: string[] };

export default async function Challenge({ params }: { params: tParams }) {
  // No need to await `params` here since it's not a Promise anymore
  const { slug } = params;
  const productID = slug[1];

  // other code here
}

Comments

0

For even the projects that run v14 have to be updated using some scenarios mentioned in here. In my case the issue was with async server components receiving params as props. Here is a general solution mentioned in the source documentation:

type Params = Promise<{ slug: string }>
type SearchParams = Promise<{ [key: string]: string | string[] | undefined }>
 
export async function generateMetadata(props: {
  params: Params
  searchParams: SearchParams
}) {
  const params = await props.params
  const searchParams = await props.searchParams
  const slug = params.slug
  const query = searchParams.query
}
 
export default async function Page(props: {
  params: Params
  searchParams: SearchParams
}) {
  const params = await props.params
  const searchParams = await props.searchParams
  const slug = params.slug
  const query = searchParams.query
}

Comments

0

You can write it like this.(App Router)

import { EventDetail } from "@/components/organisms/event-detail";

export default async function EventPage({ params }: { params: Promise<{ 
eventId: string }> }) {

    const { eventId } = await params;

    return (
        <main className="">
           <EventDetail eventId={eventId} />
        </main>
    );
}

Comments

0

Here is how fix this issue:

import Link from "next/link";
import photos, { Photo } from "@/lib/";
import PhotoCard from "@/components/photo-card";
export const generateStaticParams = () => {
  return photos.map(({ id }) => ({
    id: String(id),
  }));
};
export type paramsType = Promise<{ id: string }>;

export default async function PhotoPage(props: { params: paramsType }) {
  const { id } = await props.params;
  const photo: Photo | undefined = photos.find((p) => p.id === id);

  if (!photo) {
    return <div>Photo not found</div>;
  }

  return (
    <section className="py-24">
      <div className="container">
        <div>
          <Link
            href="/photos"
            className="font-semibold italic text-sky-600 underline"
          >
            Back to photos
          </Link>
        </div>
        <div className="mt-10 w-1/3">
          <PhotoCard photo={photo} />
        </div>
      </div>
    </section>
  );
}

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
0

Do this...

type tParams = Promise<{ slug: string }>;

export default async function ProjectPage(props: { params: tParams }) { const { slug } = await props.params;

1 Comment

As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
0

If you're facing issues during next build in Next.js 15 when using searchParams in a Server Component, make sure to define the type of searchParams properly, especially since it is now a Promise in app router server components.

Here’s how you can correctly structure your PageDonateCampaign function to avoid runtime errors and build-time issues:

export default async function PageDonateCampaign({
  searchParams,
}: {
  searchParams: Promise<{ campaign: string; fundraiserCode: string }>;
}) {
  const { campaign = "", fundraiserCode = "" } = await searchParams;

  // Now you can safely use campaign and fundraiserCode
}

🔍 Why this works: In Next.js 15, when used inside a Server Component, searchParams is passed as a Promise. You need to await it before accessing its properties. Destructuring after await like above ensures that build tools correctly recognize and compile the types.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.