How to Get the Current Pathname in the App Directory of Next.js?

When I first switched to the App Router in Next.js 13, I ran into something that left me scratching my head. I was trying to highlight the active link in my navbar something super common. In previous versions of Next.js, I used useRouter() from next/router, which gave me the handy pathname property. But when I updated my code using next/navigation (as recommended for the App Directory), I realized:

Here’s how I discovered the issue, how I fixed it, and how I made the solution more reusable and powerful. Let’s break it down.

Original Code with Error

Here’s the initial code I wrote, expecting pathname to be available:

Link from "next/link";
import { useRouter } from 'next/navigation'; // Correct for App Router

const StyledNavLink: React.FC<NavLinkProps> = ({ to, children }) => {
const router = useRouter(); // 🚨 'pathname' is not available here

return (
<Link href={to} className={getNavLinkClass({ isActive: router.pathname === to })}>
{children}
</Link>
);
};

Error:

'pathname' does not exist on type 'AppRouterInstance'

Why This Happened:

In the new App Router, useRouter() gives us navigation methods (like push() or replace()), but it no longer gives access to the current pathname. Instead, we need to use a different hook: usePathname().

Corrected Code Using usePathname()

Once I discovered the correct hook, I updated the code like this:

Link from "next/link";
import { usePathname } from 'next/navigation';

interface NavLinkProps {
to: string;
children: React.ReactNode;
}

const StyledNavLink: React.FC<NavLinkProps> = ({ to, children }) => {
const pathname = usePathname(); // This gives us the current path

const isActive = pathname === to;

return (
<Link
href={to}
className={isActive ? "text-blue-500 font-bold" : "text-gray-500"}
>
{children}
</Link>
);
};

export default StyledNavLink;

Explanation:

  • usePathname() is the new go-to method for getting the current route in the App Directory.
  • It returns a string like "/about" or "/contact".
  • I compared this with the to prop to decide whether the link is active, and applied conditional styling.

Bonus Practice Partial Match & Custom Classes

I wanted a bit more control. What if I’m on a nested route like /blog/my-post and still want the /blog link to be highlighted?

Here’s the upgraded version of the component that:

  • Supports partial matching
  • Allows custom active/inactive class names
  • Adds an optional exact prop for strict matching
Link from "next/link";
import { usePathname } from 'next/navigation';
import clsx from 'clsx'; // Optional utility for clean class handling

interface NavLinkProps {
to: string;
children: React.ReactNode;
exact?: boolean;
activeClass?: string;
inactiveClass?: string;
}

const StyledNavLink: React.FC<NavLinkProps> = ({
to,
children,
exact = false,
activeClass = "text-blue-600 font-bold",
inactiveClass = "text-gray-600",
}) => {
const pathname = usePathname();

const isActive = exact ? pathname === to : pathname.startsWith(to);

return (
<Link href={to} className={clsx(isActive ? activeClass : inactiveClass)}>
{children}
</Link>
);
};

export default StyledNavLink;

What I Added:

  • exact: Ensures a strict match (/blog !== /blog/post)
  • activeClass / inactiveClass: Lets me fully control the styling from outside
  • clsx: A great little package that makes combining classes neater

How I Used It in My App

<StyledNavLink to="/" exact>Home</StyledNavLink>
<StyledNavLink to="/about">About</StyledNavLink>
<StyledNavLink to="/blog">Blog</StyledNavLink>

This setup made my navbar dynamic and responsive to the current route, just like I wanted—clean, elegant, and App Router–friendly.

Final Thoughts

Switching to the App Directory in Next.js 13 definitely comes with a bit of a learning curve. But once I understood that useRouter() was now navigation-only and usePathname() was my new best friend, things clicked.

Related blog posts