Skip to content

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:

jsx
// 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

ApproachHookUse Case
Current pathnameusePathnameActive link highlighting
Search parametersuseSearchParamsQuery string handling

For Server Components

ApproachFeatureUse Case
Full URLheaders()Access complete URL data
Dynamic segmentsRoute params prop[slug], [id] routes

Client Component Solution

For components needing current URL pathname (like active links):

jsx
'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

  1. Place navigation components in layout files for consistent rendering
  2. Use CSS modules for active state styling
  3. Combine with useSearchParams for query string handling
jsx
'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():

jsx
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:

jsx
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:

jsx
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:

js
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 } });
}
jsx
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

  1. Server-Side usePathname Attempts
    usePathname is client-only and will fail in server components

  2. Parsing referer Manually
    Unreliable and breaks in edge cases:

    jsx
    // Avoid this pattern
    const referer = headers().get('referer');
    const pathname = new URL(referer).pathname;
  3. Client Components in Layouts
    For optimal performance, keep layouts as server components when possible

Key Takeaways

  1. Client Components: Use usePathname() from next/navigation
  2. Server Components:
    • Use headers() for static routes (x-invoke-path)
    • Use params prop for dynamic routes ([slug])
  3. Edge Cases: Employ middleware for pathname propagation
  4. 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.