Skip to main content

Next.js Link Component and Navigation

Answer

The Link component enables client-side navigation between pages in Next.js, with automatic prefetching for improved performance.

Basic Usage

import Link from "next/link";

function Navigation() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
</nav>
);
}
// ✅ Use Link for internal navigation
<Link href="/about">About</Link>
// - Client-side navigation (no full page reload)
// - Prefetches linked page
// - Preserves state

// ✅ Use <a> for external links
<a href="https://example.com" target="_blank" rel="noopener">
External Site
</a>

Dynamic Routes

function BlogList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>

{/* Or with object syntax */}
<Link
href={{
pathname: "/blog/[slug]",
query: { slug: post.slug },
}}
>
{post.title}
</Link>
</li>
))}
</ul>
);
}

Prefetching

// Prefetching is automatic by default
<Link href="/about">About</Link> // Prefetches in production

// Disable prefetching
<Link href="/large-page" prefetch={false}>
Heavy Page
</Link>

// In development, prefetching only happens on hover
// In production, links in viewport are prefetched
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";

function NavLink({ href, children }) {
const pathname = usePathname();
const isActive = pathname === href;

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

Programmatic Navigation

"use client";
import { useRouter } from "next/navigation";

function SearchForm() {
const router = useRouter();

const handleSubmit = (e) => {
e.preventDefault();
const query = e.target.query.value;

// Navigate programmatically
router.push(`/search?q=${query}`);

// Other methods:
// router.replace('/login'); // No history entry
// router.back(); // Go back
// router.forward(); // Go forward
// router.refresh(); // Refresh current route
};

return (
<form onSubmit={handleSubmit}>
<input name="query" />
<button type="submit">Search</button>
</form>
);
}

Scroll Behavior

// By default, scrolls to top on navigation
<Link href="/page">Go to Page</Link>

// Keep scroll position
<Link href="/page" scroll={false}>
Go to Page (Keep Scroll)
</Link>

// Link to anchor
<Link href="/page#section">Go to Section</Link>

Replace History

// Replace current history entry instead of pushing
<Link href="/login" replace>
Login
</Link>

// Useful for:
// - Login redirects
// - Form submissions that shouldn't be revisited

Loading States

"use client";
import { useRouter } from "next/navigation";
import { useTransition } from "react";

function SlowLink({ href, children }) {
const router = useRouter();
const [isPending, startTransition] = useTransition();

const handleClick = (e) => {
e.preventDefault();
startTransition(() => {
router.push(href);
});
};

return (
<a
href={href}
onClick={handleClick}
style={{ opacity: isPending ? 0.5 : 1 }}
>
{children}
{isPending && " (Loading...)"}
</a>
);
}

Common Patterns

// Back button
function BackButton() {
const router = useRouter();
return <button onClick={() => router.back()}>← Back</button>;
}

// Conditional navigation
function AuthLink() {
const { user } = useAuth();
return user ? (
<Link href="/dashboard">Dashboard</Link>
) : (
<Link href="/login">Login</Link>
);
}

// Navigation with params
<Link
href={{
pathname: "/products",
query: { category: "electronics", sort: "price" },
}}
>
Electronics
</Link>;
// Results in: /products?category=electronics&sort=price

Key Points

  • Use Link for internal navigation, <a> for external
  • Prefetching is automatic in production
  • Use useRouter() for programmatic navigation
  • scroll={false} to preserve scroll position
  • replace to replace history instead of pushing
  • Use usePathname() for active link styling