Back to all posts

Solving the Next.js 15 'params should be awaited' Error: A Complete Guide

If you've recently upgraded to Next.js 15 or started a new project with it, you might have encountered this frustrating error message:

Error: Route "/[locale]" used `params.locale`. `params` should be awaited before using its properties. Learn more: https://nextjs.org/docs/messages/sync-dynamic-apis

This error is appearing for many developers working with dynamic routes, internationalization, or any feature that uses route parameters. In this comprehensive guide, I'll explain exactly what changed in Next.js 15, why you're seeing this error, and provide multiple solutions to fix it properly.

What Changed in Next.js 15?

Next.js 15 introduced a significant change to how dynamic APIs work. Previously, route parameters like params and searchParams were synchronous objects that you could access directly. In version 15, these have been converted to asynchronous Promises that must be awaited before use.

This change affects:

  • The params and searchParams props in pages, layouts, and route handlers
  • Metadata API functions
  • Other dynamic APIs like cookies(), draftMode(), and headers() from next/headers

The change was made to improve performance by allowing Next.js to statically render more of your page before needing to resolve dynamic values.

Understanding the Error

The error occurs when you try to access properties of params directly without awaiting it first. For example:

// This will cause an error in Next.js 15
export default function Layout({ params }: { params: { locale: string } }) {
  const { locale } = params; // Error: params should be awaited
  return <div>{locale}</div>;
}

How to Fix the Error: Server Components

For server components (which are async by default in Next.js), the solution is straightforward:

  1. Update your type definitions to mark params as a Promise
  2. Await the params before using them

Here's how to fix it:

// Before (causes error)
export default async function Layout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  const { locale } = params; // Error!
  return (
    <html lang={locale}>
      <body>{children}</body>
    </html>
  );
}
 
// After (fixed)
export default async function Layout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params; // Correctly awaited
  return (
    <html lang={locale}>
      <body>{children}</body>
    </html>
  );
}

How to Fix the Error: Client Components

For client components (marked with 'use client'), you can't use await directly in the component body. Instead, you need to use React's use hook:

'use client'
import { use } from 'react';
 
// Before (causes error)
export default function ClientComponent({
  params
}: {
  params: { locale: string }
}) {
  const { locale } = params; // Error!
  return <div>{locale}</div>;
}
 
// After (fixed)
export default function ClientComponent({
  params
}: {
  params: Promise<{ locale: string }>
}) {
  const { locale } = use(params); // Correctly unwrapped
  return <div>{locale}</div>;
}

Automated Fix with Next.js Codemod

Next.js provides a codemod that can automatically fix many instances of this error. Run this command in your project root:

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

This will scan your codebase and update the code to properly await params. However, the codemod can't handle all cases, so you might still need to make some manual adjustments.

Special Case: Metadata Files and Route Assets

Interestingly, one of the most confusing aspects of this error is that it can appear even when you're not directly using params in your code. This happens particularly with special files like:

  • icon.png
  • opengraph-image.png
  • Other metadata files

If these files are placed inside a dynamic route folder (like /app/[locale]/icon.png), Next.js will still throw the error. The solution is to move these files outside the dynamic route folder:

# Will cause error
/app/[locale]/icon.png

# Won't cause error
/app/icon.png

This is because Next.js treats these special files as routes that might need access to the dynamic parameters.

Real-World Example: Fixing i18n Routes

Let's look at a common real-world example with internationalization:

// Before (causes error)
export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: { locale: string };
}) {
  return (
    <html lang={params.locale} dir={getDirection(params.locale)}>
      <body>
        <TranslationsProvider locale={params.locale}>
          {children}
        </TranslationsProvider>
      </body>
    </html>
  );
}
 
// After (fixed)
export default async function RootLayout({
  children,
  params,
}: {
  children: React.ReactNode;
  params: Promise<{ locale: string }>;
}) {
  const { locale } = await params;
  return (
    <html lang={locale} dir={getDirection(locale)}>
      <body>
        <TranslationsProvider locale={locale}>
          {children}
        </TranslationsProvider>
      </body>
    </html>
  );
}

Best Practices for Working with Async Params

To make your Next.js 15 code more maintainable:

  1. Define type aliases for your params to avoid repetition:

    type Params = Promise<{ locale: string }>
  2. Await params as late as possible to allow Next.js to statically render more of your page:

    export default async function Page(props: { params: Params }) {
      // Do other work first...
      const { locale } = await props.params // Await only when needed
    }
  3. Consider extracting common logic into helper functions:

    async function getLocaleFromParams(params: Promise<{ locale: string }>) {
      const { locale } = await params
      return locale
    }

Conclusion

The "params should be awaited" error in Next.js 15 is a result of a significant architectural change that makes dynamic route parameters asynchronous. While this change can be initially frustrating, it enables better performance optimizations in the framework.

To fix the error:

  1. For server components: Update types and await params
  2. For client components: Use the React.use() hook
  3. For metadata files: Move them outside dynamic route folders
  4. Consider using the Next.js codemod for automated fixes

By following these guidelines, you can successfully migrate your Next.js application to version 15 and take advantage of its performance improvements without being blocked by this common error.

Have you encountered other issues when upgrading to Next.js 15? Share your experiences in the comments below!


Did you find this article helpful? Follow me for more Next.js development tips and solutions to common web development challenges.