Fix: params are undefined in Next.js App Router Server Component
params undefined in your Next.js server component? Learn how to handle the async breaking change in Next.js 15 and properly await your dynamic route data.
FlowQL Team
AI Search Optimization Experts
You’re building a dynamic blog or product page in the Next.js App Router. You use the standard [slug] directory structure, you open your page.tsx, and you try to access the slug from the params object.
You write: const { slug } = params;
But the terminal throws a warning, your IDE shows a red squiggle, and your page crashes with: "TypeError: Cannot destructure property 'slug' of 'params' as it is undefined." Or even worse, the slug is just a blank string, and your database query fails.
This is the "Destructuring Trap."
If you are following tutorials from 2023 or 2024, or if your AI assistant (Cursor, Claude, or v0) is generating code based on older Next.js versions, you are likely missing one of the biggest architectural shifts in the App Router: Asynchronous Request APIs.
In this guide, we’ll explain why params is now a Promise, show you the correct way to access dynamic route data in Next.js 15, and provide the TypeScript patterns to keep your routes type-safe.
Breaking Change: Why Params are Now Asynchronous
To fix the bug, you have to understand the "Why."
In Next.js 13 and 14, params and searchParams were synchronous objects. You could access them immediately upon component render. However, this created a performance bottleneck for Streaming and Partial Prerendering (PPR).
By making these APIs asynchronous in Next.js 15, Vercel allows the server to start rendering parts of the page before the dynamic route data is fully resolved. This makes your pages feel significantly faster, but it breaks the old synchronous destructuring pattern.
Synchronous vs. Asynchronous Params: A Comparison
The OLD Way (Next.js 13/14 - Broken in 15)
// ❌ FAILS in Next.js 15
export default function Page({ params }: { params: { slug: string } }) {
const { slug } = params; // Error: params must be awaited
return <div>My Slug: {slug}</div>;
}
The NEW Way (Next.js 15+)
// ✅ CORRECT in Next.js 15
export default async function Page({
params
}: {
params: Promise<{ slug: string }>
}) {
const resolvedParams = await params;
const slug = resolvedParams.slug;
return <div>My Slug: {slug}</div>;
}
Common Error: Destructuring Before Awaiting
The most common mistake is trying to "shortcut" the await process. You cannot destructure a Promise directly.
// ❌ WRONG
const { slug } = await params;
While the code above might technically work in some environments, it frequently causes TypeScript errors because the type of params is defined as a Promise, not the object itself.
The Fix: How to Properly Await Params
The most robust pattern for modern Next.js development is to handle the Promise resolution at the very beginning of your component function.
Standard Pattern for Dynamic Routes:
type Props = {
params: Promise<{ id: string }>
searchParams: Promise<{ [key: string]: string | string[] | undefined }>
}
export default async function ProjectPage({ params, searchParams }: Props) {
const { id } = await params;
const { query } = await searchParams;
const data = await db.fetchProject(id);
return (
<main>
<h1>Project: {data.name}</h1>
<p>Search Query: {query}</p>
</main>
);
}
Handling searchParams in Server Components
Just like params, the searchParams (the stuff after the ? in the URL) are now asynchronous.
If your AI assistant generates a search filter like const page = searchParams.page || 1, it will fail. You must await the searchParams object before you can perform any logic or provide default values.
TypeScript Best Practices for Dynamic Routes
If you are getting the error "Property 'slug' does not exist on type Promise<{ slug: string }>", your TypeScript types are outdated.
Ensure your Props type explicitly wraps params and searchParams in a Promise. This forces you (and the AI) to remember the await keyword, preventing the "undefined" runtime error before it even happens.
FlowQL: Upgrading Your Next.js Stack without Production Failures
Next.js is evolving at an incredible pace. Patterns that were "Best Practice" six months ago are now "Legacy" or "Breaking Changes."
AI assistants are great at code, but they are often 1-2 versions behind the latest documentation. This creates a "Knowledge Gap" where the code they generate is syntactically correct but architecturally broken for your specific environment.
At FlowQL, we help companies manage these transitions. Whether you’re upgrading from the Pages Router to the App Router or moving from Next.js 14 to 15, we provide the senior technical oversight to audit your components, fix your "undefined" params, and ensure your production site remains stable.
If your "Vibe" is broken because of a framework update, it's time for a professional audit.
Conclusion
The "params are undefined" error is a signal that you are trying to use a synchronous pattern in an asynchronous world. By awaiting your params and updating your TypeScript types, you can unlock the performance benefits of Next.js 15 without the runtime crashes.
Your Action Plan:
- Check your Next.js version in
package.json. - If version 15+, find all dynamic routes.
- Update the
Propstype to usePromise. - Add the
awaitkeyword before accessing route data.
Don't let a breaking change stall your ship. [Book a session with FlowQL] and let’s get your Next.js app fully modernized.
Still blocked?
This fix didn't work for your setup? Get a senior engineer on your screen in 30 minutes.
Get a senior engineer on your screen.
30-minute live screen-share sessions with a vetted senior dev. One call, one blocker, back to shipping.
No spam. Just a heads-up when sessions open.
Related Articles
React Hook Form Not Working? 5 Fixes (2026)
Struggling with react hook form errors? This guide fixes validation not triggering, TypeScript issues, Controller bugs, and broken resets in v7.
TypeScript Enums: When to Use Them (and When Not To)
A practical guide to typescript enum patterns — numeric, string, and const enums — plus when to replace them with union types. With working code examples.
TypeScript vs JavaScript: Which Should You Use?
TypeScript vs JavaScript: understand the real differences, performance tradeoffs, and when to use each — so you can make the right call for your project.