When building any web application, navigating between pages is one of the most fundamental features. In the world of Next.js, "navigation" and "linking" are not just about moving between pages—they are a highly optimized system designed to deliver lightning-fast user experiences and SEO friendliness.
This article will help you fully master Next.js’s routing system, from the basics with the <Link>
component to advanced techniques using the useRouter
hook. Whether you’re a beginner or experienced, let’s explore together!
🥇 Golden Rule: Client-Side Navigation
Before diving into details, you need to grasp the most important concept: Client-Side Navigation.
In traditional websites, every time you click a link, the browser sends a request to the server and reloads the entire HTML, CSS, and JavaScript. This causes a delay and a white "flicker" on the screen.
Next.js solves this problem smartly. When you use its navigation tools:
- The initial page is rendered from the server (Server-Side Rendering - SSR) for fast load and SEO.
- Then, the React (Next.js) app "hydrates" in the browser.
- All subsequent navigation happens on the client. Next.js only fetches the JavaScript needed for the new page and updates the DOM without reloading the whole page.
The result? An instant, smooth user experience, with no interruptions—just like a native mobile app.
🔗 The Foundation of All Links: The <Link>
Component
The most basic and powerful tool for navigation in Next.js is the <Link>
component. Instead of using a regular <a>
tag, you wrap it with <Link>
.
Basic Syntax
The simplest usage is to pass a path string to the href
prop.
import Link from 'next/link'
function Navbar() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
)
}
Why not use <a>
directly?
When you use <Link>
, Next.js handles everything for you:
- Client-Side Navigation: Enables client-side routing.
- Prefetching: This is a killer feature! When a
<Link>
component appears in the user’s viewport, Next.js automatically preloads the code for that page in the background. When the user actually clicks the link, the page is ready to display instantly. This is one of the secrets to Next.js’s speed.
Navigating to Dynamic Pages
Most apps have dynamic pages, e.g., /blog/[slug]
, /products/[id]
. Linking to them is simple.
import Link from 'next/link'
function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
{/* Use template literals for dynamic paths */}
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
You can also pass an object to href
for more options, such as query parameters:
<Link
href={{
pathname: '/shop/search',
query: { category: 'electronics', sort: 'price_asc' },
}}
>
Find electronics sorted by price
</Link>
// Equivalent to: /shop/search?category=electronics&sort=price_asc
⚡ Flexible Navigation: The useRouter
and usePathname
Hooks
Navigation isn’t always triggered by a click on a link. Sometimes you need to redirect after an action, such as submitting a form or completing a transaction. This is where hooks come in.
Important note: The syntax for these hooks differs slightly between the App Router (Next.js 13+) and the Pages Router (older versions).
For App Router (Next.js 13+)
In the App Router, import hooks from next/navigation
:
useRouter()
: Provides methods for programmatic navigation.usePathname()
: Returns the current URL path.useSearchParams()
: Lets you read URL query parameters.
Example: Redirect after login
'use client' // Required for components using hooks
import { useRouter } from 'next/navigation'
export default function LoginForm() {
const router = useRouter()
const handleSubmit = async (event) => {
event.preventDefault()
// User authentication logic...
const isAuthenticated = true // Assume login is successful
if (isAuthenticated) {
// Redirect user to dashboard
router.push('/dashboard')
}
}
return (
<form onSubmit={handleSubmit}>
{/* Input fields... */}
<button type="submit">Login</button>
</form>
)
}
Useful router
methods:
router.push('/path')
: Pushes a new route onto the history stack. The user can go back.router.replace('/path')
: Replaces the current route. The user cannot go back (useful for login/signup).router.refresh()
: Reloads the latest data for the current route from the server without losing client state.router.back()
: Goes back to the previous page in history.router.forward()
: Goes forward in history.
✨ Advanced Techniques and Tips
1. Marking the Active Link
A common requirement is to style the link corresponding to the current page. The usePathname
hook is perfect for this.
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
import './styles.css' // Assume you have a CSS file with an 'active' class
export default function NavLink({ href, children }) {
const pathname = usePathname()
const isActive = pathname === href
return (
<Link href={href} className={isActive ? 'active' : ''}>
{children}
</Link>
)
}
2. Disabling Prefetching
Sometimes, you may not want to preload a page (e.g., a heavy page that’s rarely visited). You can turn this off:
<Link href="/heavy-page" prefetch={false}>
Heavy Page
</Link>
3. Controlling Scroll Behavior (Scroll Restoration)
By default, Next.js scrolls to the top of the new page when you navigate. You can change this with the scroll
prop.
// When clicked, the page will not scroll to the top
<Link href="/#section-three" scroll={false}>
Go to Section 3
</Link>
For Pages Router (Older Next.js)
If you’re working with an older project using the Pages Router, the concepts are similar but hooks are imported from next/router
.
import { useRouter } from 'next/router'
function MyComponent() {
const router = useRouter()
// Get path: router.pathname
// Get query: router.query
// Navigate: router.push('/path')
// Example: get slug from dynamic URL /blog/[slug]
const { slug } = router.query
return <p>This is the post: {slug}</p>
}
Conclusion: Mastering Navigation and Linking is Easy
Before wrapping up, here’s a quick comparison table of the key features:
Feature | <Link> Component | useRouter Hook (App Router) |
---|---|---|
Purpose | User-initiated navigation (clicks). | Programmatic navigation (after events, logic). |
Usage | <Link href="/path">...</Link> | const router = useRouter(); router.push('/path'); |
Prefetching | Enabled by default. | Not applicable. |
SEO | Excellent, crawlers can read the <a> inside. | No direct SEO impact. |
When to use | Navbars, post lists, internal links. | After form submit, login/logout, logic actions. |
The navigation and linking system in Next.js is a perfect blend of simplicity and power. By leveraging Client-Side Navigation, the <Link>
component with smart prefetching, and the flexibility of the useRouter
hook, you can build web apps with smooth, fast, and seamless user experiences.
Understanding and using these tools correctly not only improves your app’s performance but is also the key to creating professional products that win over even the most demanding users.
Good luck mastering Next.js!