Eimantas Petrikas
Eimantas Petrikas

Reputation: 185

Route "/[locale]" used `params.locale`. `params` should be awaited before using its properties

I'm working on a Next.js 15 app using the new App Router (app directory) with dynamic route localization. I have a [locale] directory where I handle multiple language routes, and I use the params object to access the locale value. However, I keep getting the following error when trying to access params.locale:

Error: Route "/[locale]" used `params.locale`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis
    at locale (webpack:///app/[locale]/layout.tsx?a262:30:34)

Code Structure Here's the structure of my app:

app/
├── [locale]/
│   ├── layout.tsx            // Root layout for [locale] dynamic route
│   └── page.tsx              // Main page component for [locale] dynamic route
locales/
├── en/
│   └── common.json           // English translations
├── lt/
│   └── common.json           // Lithuanian translations
i18Config.js                  // i18n configuration with available locales
i18n.js                       // i18n initialization file
TranslationsProvider.js       // Translation provider component
middleware.js                 // Middleware to handle locale-based redirection

In app/[locale]/layout.tsx, I want to access the locale value from params and pass it to different components. I have tried various ways to access params, but the error persists.

Here's what my layout.tsx file looks like:

import "@/styles/global.css";
import { Outfit } from "next/font/google";
import { Providers } from "./providers";
import i18nConfig from "../../i18nConfig";
import { dir } from "i18next";

const outfit = Outfit({
  subsets: ["latin"],
  weight: ["300", "400", "500", "600", "700", "800"],
  style: ["normal"],
});

export function generateStaticParams() {
  return i18nConfig.locales.map((locale) => ({ locale }));
}

export default async function RootLayout({
  children,
  params: { locale },
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  return (
    <html
      lang={locale}
      dir={dir(locale)}
      suppressHydrationWarning
      className={outfit.className}
    >
      <body className="bg-background">
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

  1. Accessing params directly in the function body: I've moved params.locale to a separate constant in the function body, but the error still appears.
  2. Using generateStaticParams: I added generateStaticParams to pre-generate routes for the available locales (en and lt). This didn't resolve the error either.
  3. Type Adjustments: I created a custom type for params to ensure TypeScript knows the structure of params (i.e., params: { locale: string }).

The error suggests that params should be "awaited," even though params is an object and not a promise, so await params doesn’t make sense here. I’ve seen other posts mentioning that destructuring in async functions can cause issues with params in Next.js, but accessing params directly also didn’t work for me. Restarting the server after every change didn’t resolve the issue either.

How can I correctly access params.locale in a dynamic route layout without getting this error? Is there a workaround or configuration I’m missing? Any insight would be greatly appreciated. Thank you!

Upvotes: 16

Views: 9178

Answers (6)

Diego Celis
Diego Celis

Reputation: 1

In my case it was solved with this command

$ npx @next/codemod@canary next-async-request-api .

Upvotes: 0

Fred Vanelli
Fred Vanelli

Reputation: 767

I just found the problem (and it makes no sense at all).

This is the layout.tsx code and it seems to be correct:

export default async function RootLayout({
  children,
  params,
}: RootLayoutProps) {
  const { lang } = await params

  return (
    <html lang={lang}>
      <body>{children}</body>
    </html>
  )
}

In my case, the icon.png file was triggering the warning.

With warning:

/src
├── /app
│   ├── /[lang]
│   │    ├── layout.tsx
│   │    └── icon.png

Without warning:

/src
├── /app
│   ├── icon.png
│   ├── /[lang]
│   │    └── layout.tsx

That's it:

  • /app/[lang]/icon.png - Warning
  • /app/icon.png - No warning

Upvotes: 4

Santiago Rueda Ortiz
Santiago Rueda Ortiz

Reputation: 21

For reference, what you need to await is the params because, as Next15 Dynamic APIs are Asynchronous Official Docs

For example, you have a Page Component getting the id from the params like

export default async function Page(props: { params: { id: string } }) 

Then it would have to change to a Promise type like this:

export default async function Page(props: { params: Promise<{ id: string }> }) 

And access through the await of params like this:

const { id } = await props.params;

Upvotes: 1

forest
forest

Reputation: 13

export default async function RootLayout({
  children,
  params,
}: RootLayoutProps) {
  const locale = (await params).locale

  return (
    <html lang={lang}>
      <body>{children}</body>
    </html>
  )
}

Upvotes: 0

Raja Jahanzaib
Raja Jahanzaib

Reputation: 518

As of Next.js version 15 you must await the params to resolve this. Here is an example:

export default async function RootLayout({children, params }: { children: React.ReactNode; params: Promise<{ locale: string }> }) {
  const { locale } = await params;
  return()
}

let me know if it works for you.

Upvotes: 19

Leonardo Barbosa
Leonardo Barbosa

Reputation: 1396

You should await params, like:

export async function POST(request: Request, { params }: { params: Promise<{ unit_id: string }> }) {

and then:

const { unit_id: unitId } = await params

for example.

Upvotes: 1

Related Questions