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
useSearchParams
for 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
usePathname
AttemptsusePathname
is client-only and will fail in server componentsParsing
referer
Manually
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
params
prop 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.