ctan-dev/nextjsdynamicroutes icon
public
Published on 5/22/2025
Next.js 15+ Dynamic Routes Rules

Rules
CRITICAL: In Next.js 15+, the `params` prop is a Promise and MUST be handled asynchronously. Follow these rules:

1. ALWAYS type params as Promise:
   - Single param: Promise<{ slug: string }>
   - Multiple params: Promise<{ categoryId: string; itemId: string }>
   - Catch-all: Promise<{ slug: string[] }>
   - Optional catch-all: Promise<{ slug?: string[] }>

2. ALWAYS use async/await pattern:
   - Make component function async: export default async function MyPage({ params })
   - Await params before accessing: const { slug } = await params;
   - NEVER access params directly: params.slug is INCORRECT

3. Apply to ALL dynamic route files:
   - Pages: app/[slug]/page.tsx
   - Layouts: app/[slug]/layout.tsx  
   - Route handlers: app/api/[id]/route.ts
   - All HTTP methods (GET, POST, PUT, DELETE, etc.)

4. Alternative: Use React's use() hook:
   - Import: import { use } from 'react';
   - Usage: const { slug } = use(params);

5. Proper error handling:
   - Wrap in try/catch: try { const { slug } = await params; } catch { return <ErrorPage />; }

6. generateStaticParams should return objects matching param structure:
   - [slug] → [{ slug: 'value' }]
   - [categoryId]/[itemId] → [{ categoryId: 'cat', itemId: 'item' }]

7. FORBIDDEN patterns (will cause errors):
   - const { slug } = params; // Synchronous access
   - params.slug // Direct property access
   - Non-async functions with param access

Remember: Synchronous access is deprecated in Next.js 15+ and will be removed.