Get Current Pathname in Next.js App Router
Problem Statement
When migrating to Next.js 13+ with the App Router, developers lose access to router.pathname from next/router. This commonly breaks navigation patterns like:
// Previously in Pages Router:
import { useRouter } from 'next/router';
function Component() {
const router = useRouter();
const isActive = router.pathname === '/about';
}Missing the pathname property causes:
- Active link highlighting failures
- Type errors:
Property 'pathname' does not exist on type 'AppRouterInstance' - Navigation logic breaks in App Router components
App Router Changes
The next/navigation module replaces next/router but omits pathname, requiring new techniques for URL information
Solution Overview
For Client Components
| Approach | Hook | Use Case |
|---|---|---|
| Current pathname | usePathname | Active link highlighting |
| Search parameters | useSearchParams | Query string handling |
For Server Components
| Approach | Feature | Use Case |
|---|---|---|
| Full URL | headers() | Access complete URL data |
| Dynamic segments | Route params prop | [slug], [id] routes |
Client Component Solution
For components needing current URL pathname (like active links):
'use client';
import { usePathname } from 'next/navigation';
import Link from 'next/link';
export default function Navbar() {
const pathname = usePathname();
return (
<nav>
<Link
href="/"
className={pathname === '/' ? 'active' : ''}
>
Home
</Link>
<Link
href="/about"
className={pathname === '/about' ? 'active' : ''}
>
About
</Link>
</nav>
);
}Best Practices
- Place navigation components in layout files for consistent rendering
- Use CSS modules for active state styling
- Combine with
useSearchParamsfor query string handling
'use client';
import { usePathname, useSearchParams } from 'next/navigation';
function Example() {
const pathname = usePathname();
const searchParams = useSearchParams();
const id = searchParams.get('id');
}Server Component Solutions
Using Headers API
Access full URL information in server components via headers():
import { headers } from 'next/headers';
export default function Layout({ children }) {
const headersList = headers();
const pathname = headersList.get('x-invoke-path') || '/';
const fullUrl = headersList.get('referer') || '';
return (
<div>
<Header activePath={pathname} />
{children}
</div>
);
}Accessing Dynamic Routes
For routes like /products/[id], access parameters directly:
export default function ProductPage({ params }) {
return <h1>Product ID: {params.id}</h1>;
}Next.js 15+ Asynchronous Note
In Next.js 15+, dynamic routes are asynchronous. Use await with dynamic parameters:
export default async function Page({ params }) {
const { username } = await params;
return <div>Username: {username}</div>;
}Alternative Approaches
Middleware Solution
For advanced cases needing pathname across routes:
import { NextResponse } from 'next/server';
export function middleware(request) {
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-pathname', request.nextUrl.pathname);
return NextResponse.next({ request: { headers: requestHeaders } });
}import { headers } from 'next/headers';
export default function Page() {
const pathname = headers().get('x-pathname');
return <div>Current path: {pathname}</div>;
}Common Pitfalls
Avoid These Anti-Patterns
Server-Side
usePathnameAttemptsusePathnameis client-only and will fail in server componentsParsing
refererManually
Unreliable and breaks in edge cases:jsx// Avoid this pattern const referer = headers().get('referer'); const pathname = new URL(referer).pathname;Client Components in Layouts
For optimal performance, keep layouts as server components when possible
Key Takeaways
- Client Components: Use
usePathname()fromnext/navigation - Server Components:
- Use
headers()for static routes (x-invoke-path) - Use
paramsprop for dynamic routes ([slug])
- Use
- Edge Cases: Employ middleware for pathname propagation
- Next.js 15+: Remember dynamic routes are now asynchronous
By following these patterns, you can effectively manage URL state in modern Next.js applications while maintaining optimal performance and developer experience.