How to fix Next.js 15 route export type errors

by Dan Edwards, 11 November 2024

How to fix Next.js 15 route export type errors

When working with Next.js 15 API routes, you might encounter a TypeScript error stating that your route has an invalid export. Specifically, you might see this error during the build:

Command line
Creating an optimized production build ...
 ✓ Compiled successfully
   Linting and checking validity of types  ..Failed to compile.

src/app/api/articles/[slug]/route.ts
Type error: Route "src/app/api/articles/[slug]/route.ts" has an invalid "GET" export:
  Type "Props" is not a valid type for the function's second argument.

This error occurs when using the traditional approach to typing route parameters:

src/app/api/articles/[slug]/route.ts
TypeScript
1// 🚫 This approach no longer works in Next.js 15
2
3import { NextRequest } from 'next/server'
4import { getArticleBySlug } from '@/library/articles'
5
6type Props = {
7 params: {
8   slug: string
9 }
10}
11
12export async function GET(
13 req: NextRequest,
14 props: Props
15): Promise<NextResponse> {
16 try {
17   const article = await getArticleBySlug(
18     props.params.slug
19   )
20   // ...rest of the handler
21 } catch (error) {
22   // error handling
23 }
24}

The Solution

In Next.js 15, route parameters are now handled as a Promise. Here's the correct way to type and handle them:

src/app/api/articles/[slug]/route.ts
TypeScript
1// ✅ The correct approach for Next.js 15
2
3import { NextRequest, NextResponse } from 'next/server'
4import { getArticleBySlug } from '@/library/articles'
5
6export async function GET(
7 request: NextRequest,
8 { params }: { params: Promise<{ slug: string }> }
9): Promise<NextResponse> {
10 try {
11   const { slug } = await params
12   // ...rest of the handler
13 } catch (error) {
14   // error handling
15 }
16}

Key changes explained

  1. Promise Type: The params object is now typed as a Promise:
    route.ts
    TypeScript
    { params: Promise<{ slug: string }> }
  2. Await Parameters: You must await the params before accessing any parameter properties:
    route.ts
    TypeScript
    // Destructure specific parameters
    const { slug } = await params
    
    // Get all resolved parameters at once
    const resolvedParams = await params

Verification

After implementing these changes, your Next.js build should be completed successfully. You should see output similar to:

Command line
> next build

   ▲ Next.js 15.0.3
   - Environments: .env

   Creating an optimized production build ...
 ✓ Compiled successfully
 ✓ Linting and checking validity of types    
 ✓ Collecting page data    
 ✓ Generating static pages (11/11)
 ✓ Collecting build traces    
 ✓ Finalizing page optimization    

Route (app)                                Size     First Load JS
┌ ○ /                                      174 B           109 kB
├ ○ /_not-found                            897 B           101 kB
├ ○ /admin                                 1.26 kB         101 kB
├ ƒ /api/articles                          142 B           100 kB
├ ƒ /api/articles/[slug]                   142 B           100 kB
├ ƒ /api/regenerate                        142 B           100 kB
└ ● /articles/[slug]                       174 B           109 kB
    ├ /articles/created-from-my-phone
    ├ /articles/generated-without-vs-code
    ├ /articles/article-two
    └ /articles/article-one
+ First Load JS shared by all              99.9 kB
  ├ chunks/0759e794-56e8ed065b5f0a78.js    52.5 kB
  ├ chunks/743-7bb82a2990e2d984.js         45.6 kB
  └ other shared chunks (total)            1.88 kB


○  (Static)   prerendered as static content
●  (SSG)      prerendered as static HTML (uses generateStaticParams)
ƒ  (Dynamic)  server-rendered on demand

dan@Dans-MacBook-Pro incremental-regeneration %

Additional Notes

  • This change affects all dynamic API routes in Next.js 15
  • The Promise typing allows for better handling of asynchronous route parameter resolution
  • Make sure to handle Promise rejection cases in your error handling properly
  • This approach works with both single and multiple dynamic segments

By following this updated typing pattern, you'll resolve the export type error and ensure your dynamic API routes work correctly in Next.js 15.