Next.js Link and Navigation
Use the Link component, useRouter, and redirects for fast navigation between pages in Next.js.
TL;DR
- Navigate between pages with
<Link href>instead of a plain anchor tag. - Read the current path in Client Components with
usePathname(). - Redirect on the server by calling
redirect()fromnext/navigation.
The Link Component
<Link href>Navigate on the client and prefetch the target route in the background.
import Link from 'next/link';
export default function Nav() {
return <Link href="/dashboard">Dashboard</Link>;
}Dynamic hrefBuild the path with a template string when linking to a dynamic route.
{posts.map((post) => (
<Link key={post.id} href={`/blog/${post.slug}`}>
{post.title}
</Link>
))}replace and scrollReplace the history entry or keep the scroll position during navigation.
<Link href="/step-2" replace>
Next step
</Link>
<Link href="/feed?tab=new" scroll={false}>
New
</Link>Active Links and URL State
usePathname()Read the current path in a Client Component to style the active link.
'use client';
import { usePathname } from 'next/navigation';
import Link from 'next/link';
export function NavLink({ href }: { href: string }) {
const active = usePathname() === href;
const current = active ? 'page' : undefined;
return (
<Link href={href} aria-current={current}>
{href}
</Link>
);
}useSearchParams()Read query string values in a Client Component wrapped in Suspense.
'use client';
import { useSearchParams } from 'next/navigation';
export function Query() {
const q = useSearchParams().get('q');
return <p>Searching for {q}</p>;
}Update the QueryPush a new URL to store filter or search state in the query string.
const router = useRouter();
const params = new URLSearchParams();
params.set('sort', 'price');
router.push(`/products?${params}`);Programmatic Navigation
useRouter()Navigate from an event handler in a Client Component with router.push.
'use client';
import { useRouter } from 'next/navigation';
export function LoginButton() {
const router = useRouter();
return (
<button onClick={() => router.push('/login')}>
Log in
</button>
);
}router methodsGo back, replace the current entry, or reload fresh data from the server.
router.back(); // previous page
router.replace('/'); // no history entry
router.refresh(); // refetch server dataredirect()Send the user to another route from a Server Component or Server Action.
import { redirect } from 'next/navigation';
export default async function Page() {
const user = await getUser();
if (!user) redirect('/login');
return <h1>Welcome, {user.name}</h1>;
}Prefetching and Feedback
prefetchTurn off automatic prefetching for a link that users rarely click.
<Link href="/archive" prefetch={false}>
Archive
</Link>useLinkStatus()Show a pending hint inside a link while its navigation is in progress.
'use client';
import { useLinkStatus } from 'next/link';
export function Hint() {
const { pending } = useLinkStatus();
return pending ? <span>Loading...</span> : null;
}router.prefetch()Prefetch a route yourself when you know the user is about to visit it.
const router = useRouter();
<button onMouseEnter={() => router.prefetch('/cart')}>
View cart
</button>Tips
- Use
<Link>for anything a user can click, and keepuseRouter()for navigation that happens after an event such as a form submit. - Set
prefetch={false}on links in very long lists, so the browser does not prefetch hundreds of routes at once.
Warnings
- Import
useRouterfromnext/navigationin the App Router, because thenext/routerversion only works in the Pages Router. - Calling
redirect()inside atryblock fails, because it works by throwing an error that yourcatchwould swallow.
In Practice
Build a navigation bar that highlights the page the user is currently on.
- The file is a Client Component because usePathname is a hook.
- The links array keeps the paths and labels in one place.
- Comparing the path to each href decides which link is active.
- aria-current tells screen readers which link is the current page.
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
const links = [
['/', 'Home'], ['/blog', 'Blog'], ['/about', 'About'],
];
export function NavBar() {
const path = usePathname();
return (
<nav>
{links.map(([href, label]) => {
const current = path === href ? 'page' : undefined;
return (
<Link key={href} href={href} aria-current={current}>
{label}
</Link>
);
})}
</nav>
);
}FAQ
In a Client Component, call useRouter() from next/navigation and use router.push('/path'). On the server, call redirect('/path') instead.
Call usePathname() in a Client Component and compare it to the link's href. Apply an active class when the two match.
Reading the query string can only happen at request time. Wrapping the component in lets the rest of the page render first while that part waits.