Linking and Navigation in Next.js (next/link, next/navigation)
You now know how to define routes using files and folders, but how do users actually move between them? You could use a plain HTML <a> tag, and it would technically work — but it would trigger a full page reload every time, discarding all of Next.js's performance advantages: no shared layout persistence, no client-side caching, no instant transitions. Next.js provides its own navigation tools specifically designed to preserve these benefits.
This lesson covers the three tools you'll use for navigation: the Link component for standard clickable navigation, the useRouter hook for navigating programmatically (like after a form submits successfully), and the usePathname hook for reading the current URL, commonly used to highlight an active navigation item.
Learning Objectives
- Use the Link component to navigate between pages without full page reloads.
- Explain why Link is preferred over a plain <a> tag for internal navigation.
- Use the useRouter hook to navigate programmatically in response to code logic.
- Use the usePathname hook to read and react to the current URL path.
- Build an active navigation link pattern using usePathname.
Core Definitions
- next/link (Link component): A built-in Next.js component that enables client-side navigation between routes, preventing full page reloads.
- Client-side navigation: Navigating between routes using JavaScript in the browser, without requesting a fresh full HTML document from the server.
- useRouter: A hook from next/navigation that provides programmatic navigation methods like push and back, for use inside Client Components.
- usePathname: A hook from next/navigation that returns the current URL's pathname as a string, useful for conditional logic like highlighting active links.
- Prefetching: Next.js's default behavior of automatically loading a linked page's code in the background when a Link enters the viewport, making the eventual navigation feel instant.
Detailed Explanation
The Link component, imported from next/link, is the primary way to navigate between pages in a Next.js application. Visually and semantically it renders as an <a> tag under the hood (so it's accessible and works with right-click 'open in new tab'), but it intercepts the click event and performs client-side navigation using JavaScript instead of triggering a full browser page reload. This preserves everything the App Router optimizes for: shared layouts don't remount, and by default Next.js prefetches the linked page's code as soon as the Link scrolls into view, so by the time a user actually clicks, the transition feels instant.
Using a plain <a href="/about"> tag instead of Link would still technically navigate the user to /about, but it would force a full page reload — re-downloading and re-executing the entire application from scratch, discarding the performance benefits Next.js is specifically designed to provide. This is why Link is strongly preferred for any internal navigation within your app; plain <a> tags are still appropriate for external links leaving your site.
Sometimes navigation needs to happen as a result of code logic rather than a direct user click — for example, redirecting a user to a dashboard after a successful login form submission. This is what useRouter, imported from next/navigation, is for. Calling router.push('/dashboard') programmatically navigates the user, while router.back() and router.forward() move through browser history, similar to the browser's back/forward buttons. useRouter can only be used inside Client Components, since it depends on browser-side interactivity.
usePathname, also from next/navigation, returns the current URL's pathname as a plain string (e.g., '/dashboard/settings'). It's most commonly used to build 'active link' styling — comparing the current pathname against each navigation link's href to determine which one should be visually highlighted as the current page.
Diagram Description
Visualize the three navigation tools and their use cases:
[Link component] → User clicks a visible link → Client-side nav, prefetches automatically
[useRouter().push()] → Code triggers navigation → e.g., after form submit success
[usePathname()] → Read current URL → e.g., highlight active nav item
Flow example:
User on '/dashboard' clicks <Link href='/dashboard/billing'>
→ No full page reload
→ Shared DashboardLayout stays mounted
→ Only inner page content swaps to Billing page
→ usePathname() in Sidebar now returns '/dashboard/billing', highlighting 'Billing' link
Comparison Table
| Tool | Import From | Use Case | Works In |
|---|---|---|---|
| Link | next/link | Standard clickable navigation between pages | Server or Client Components |
| useRouter | next/navigation | Programmatic navigation triggered by code logic | Client Components only |
| usePathname | next/navigation | Reading the current URL path, e.g. for active links | Client Components only |
Next.js Practical Example
// components/Navbar.tsx — using Link + usePathname for active link styling
'use client';
import Link from 'next/link';
import { usePathname } from 'next/navigation';
const links = [
{ href: '/', label: 'Home' },
{ href: '/dashboard', label: 'Dashboard' },
{ href: '/about', label: 'About' },
];
export default function Navbar() {
const pathname = usePathname();
return (
<nav>
{links.map((link) => (
<Link
key={link.href}
href={link.href}
style={{ fontWeight: pathname === link.href ? 'bold' : 'normal' }}
>
{link.label}
</Link>
))}
</nav>
);
}
// app/login/page.tsx — using useRouter for programmatic navigation
'use client';
import { useRouter } from 'next/navigation';
export default function LoginPage() {
const router = useRouter();
async function handleLogin() {
const success = await fakeLoginRequest();
if (success) {
router.push('/dashboard'); // navigate after successful login
}
}
return <button onClick={handleLogin}>Log In</button>;
}
In Navbar, each Link renders a normal-looking anchor tag but navigates client-side, preserving the app's performance benefits. usePathname reads the current URL on every render, and the component compares it against each link's href to bold the active page's link — a pattern used constantly in real navigation bars. In LoginPage, navigation isn't triggered by a user clicking a Link directly; instead, handleLogin runs custom logic first (an async login request), and only calls router.push('/dashboard') once that logic confirms success — something a plain Link component, which navigates immediately on click, could not conditionally do.
Industry Examples
- E-commerce sites use Link for product grid navigation so that browsing between dozens of products feels instant thanks to Next.js's automatic prefetching.
- SaaS applications use useRouter to redirect users to a dashboard immediately after successful authentication, subscription checkout, or onboarding completion.
- Sidebar navigation in admin panels and documentation sites almost universally uses usePathname to bold or highlight the currently active section.
- Multi-step forms and wizards use router.push to move users to the next step programmatically after validating the current step's input.
- Marketing sites use Link with prefetching so that hovering over navigation items (like Pricing or Features) loads that page's code before the user even clicks, creating a near-instant perceived load time.
Interview Questions and Answers
Q1. Why should you use the Link component instead of a plain <a> tag for internal navigation in Next.js?
The Link component performs client-side navigation, avoiding a full page reload, preserving shared layout state, and enabling automatic prefetching of the linked page's code for near-instant transitions. A plain <a> tag triggers a full browser page reload, discarding these performance benefits, even though the destination is technically still reached.
Q2. What is the difference between the Link component and the useRouter hook?
Link is a component used for standard, user-clickable navigation rendered directly in JSX. useRouter is a hook that provides programmatic navigation methods like push(), used when navigation needs to happen as a result of code logic, such as after a successful form submission, rather than a direct link click.
Q3. What does usePathname return and what is it typically used for?
usePathname returns the current URL's pathname as a string, such as '/dashboard/settings'. It's commonly used to compare against navigation links' href values to determine and visually highlight which link corresponds to the currently active page.
Q4. Can useRouter and usePathname be used in Server Components?
No. Both hooks require the 'use client' directive because they depend on client-side, browser-based interactivity and the current navigation state, which Server Components, rendered only on the server, do not have access to.
Q5. What is prefetching in the context of the Next.js Link component?
Prefetching is Next.js's default behavior of automatically loading a linked page's code in the background once a Link component enters the user's viewport, so that by the time the user actually clicks it, the navigation feels instantaneous.
MCQs With Answers
1. Which component should be used for standard internal navigation in Next.js to avoid full page reloads?
- <a>
- <Link>
- <Navigate>
- <Route>
Answer: B. <Link>
Explanation: The Link component from next/link performs client-side navigation, avoiding full page reloads and preserving Next.js's performance optimizations, unlike a plain <a> tag.
2. Which hook would you use to navigate a user to a new page after a successful form submission?
- usePathname
- useRouter
- useState
- useEffect
Answer: B. useRouter
Explanation: useRouter provides programmatic navigation methods like push(), ideal for navigating in response to code logic such as a successful form submission.
3. What does usePathname return?
- The full URL including domain
- The current URL's pathname as a string
- A list of all site routes
- The previous page's URL
Answer: B. The current URL's pathname as a string
Explanation: usePathname returns just the pathname portion of the current URL, such as '/dashboard/settings', without the domain or query string.
4. What happens by default when a Link component scrolls into the user's viewport?
- Nothing until clicked
- Next.js prefetches the linked page's code
- The page reloads immediately
- An error is logged
Answer: B. Next.js prefetches the linked page's code
Explanation: Next.js automatically prefetches a linked page's code once its Link enters the viewport, making the eventual click-triggered navigation feel instant.
5. Where can useRouter and usePathname be used?
- Anywhere, including Server Components
- Only in Client Components
- Only inside layout.tsx files
- Only in API routes
Answer: B. Only in Client Components
Explanation: Both hooks depend on client-side interactivity and require the 'use client' directive; they cannot be used in Server Components.
Common Mistakes to Avoid
- Using a plain <a> tag for internal navigation, causing unnecessary full page reloads and losing layout persistence and prefetching benefits.
- Trying to use useRouter or usePathname inside a Server Component without adding the 'use client' directive.
- Confusing useRouter's push() (which adds a new history entry) with replace() (which replaces the current entry) when the intended browser back-button behavior differs.
- Forgetting that Link should still be used for most navigation, reserving useRouter for cases that genuinely require programmatic, logic-driven navigation.
- Using external, full URLs (like https://example.com) with the Link component, when plain <a> tags are more appropriate for navigation leaving the app entirely.
Interview Notes
- Link (from next/link) performs client-side navigation, avoiding full page reloads and preserving layout state.
- useRouter (from next/navigation) provides programmatic navigation methods like push(), back(), and forward(), and requires 'use client'.
- usePathname (from next/navigation) returns the current URL's pathname as a string and also requires 'use client'.
- Next.js automatically prefetches a Link's destination once it enters the viewport, for near-instant subsequent navigation.
- Plain <a> tags remain appropriate for external links leaving the application.
Key Takeaways
- Link is the default, preferred way to navigate within a Next.js app, preserving all of the App Router's performance benefits.
- useRouter exists specifically for navigation triggered by logic rather than a direct link click, such as after an async operation succeeds.
- usePathname is the standard tool for building active-link styling and other current-route-aware UI logic.
- All three tools work together in real applications: Link for the visible navigation menu, usePathname to highlight the active item, and useRouter for logic-driven redirects elsewhere in the app.
Summary
Navigating between Next.js pages should almost always use the Link component from next/link rather than a plain <a> tag, since Link performs client-side navigation that avoids full page reloads, preserves shared layout state, and automatically prefetches linked pages for near-instant transitions. When navigation needs to happen programmatically — as a result of code logic like a successful form submission — the useRouter hook from next/navigation provides methods like push() for this purpose. The usePathname hook, also from next/navigation, returns the current URL's pathname as a string, commonly used to build active-link highlighting in navigation menus. Both useRouter and usePathname require the 'use client' directive since they depend on client-side interactivity, unlike the Link component, which can be used in both Server and Client Components.