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.
FAQ: Next.js Params and Async APIs
Q: Do I need to await params in Client Components?
A: Yes. In Next.js 15, the useParams() hook in Client Components is still synchronous, but the params prop passed to the page itself is asynchronous. It is best practice to use the use hook from React: const { slug } = use(params);.
Q: Why did Vercel make this change? A: To enable Streaming. By making params async, Next.js can send the layout and loading state to the browser before it even knows which specific ID it is looking for.
Q: Can I go back to synchronous params? A: No. While you can stay on Next.js 14, the ecosystem is moving toward async request APIs. It is better to refactor your components now than to fight the framework later.
Subscribe to our blog
Get the latest guides and insights delivered to your inbox.
Join the FlowQL waitlist
Get early access to our AI search optimization platform.
Related Articles
Fix: 'NextRouter was not mounted' in Next.js App Directory
Getting the 'NextRouter was not mounted' error? Learn why next/router fails in the App Router and how to correctly use next/navigation for Next.js 14 and 15.
Shadcn UI 'Component Not Found' After Installation - Fixed (2025 Guide)
Shadcn component not found after install? This guide covers path alias fixes, components.json configuration, TypeScript mapping errors, and when to escalate beyond DIY debugging.
Fix 'Hydration Failed Because the Initial UI Does Not Match' in Next.js 14 (2025 Guide)
Next.js hydration failed error? This comprehensive guide covers 8 root causes, 5 quick fixes, systematic debugging workflow, and when AI tools can't see the invisible wall between server and client.