Next.js provides three navigation methods — the <Link> component for declarative navigation with automatic prefetching, useRouter() for programmatic navigation in event handlers, and redirect() for server-side redirects in Server Components and actions.
Extends <a> with automatic prefetching and client-side navigation — links in the viewport are prefetched, clicking updates only changed segments.
Programmatic navigation in Client Components — push(), replace(), back(), refresh(). Import from next/navigation, not next/router.
Server-side redirects in Server Components and actions — throws internally (can't try/catch). 307 temporary, permanentRedirect() for 308.
Navigation updates only changed segments while preserving shared layouts and React state — no full page reload.
Next.js provides several navigation mechanisms, each designed for a specific use case. The key differentiator from plain React is automatic prefetching and client-side transitions that preserve state.
<Link> ComponentThe primary navigation mechanism — renders an <a> tag with automatic prefetching and client-side navigation:
import Link from 'next/link';
<Link href="/about">About</Link>
<Link href="/blog/hello-world">Blog Post</Link>
<Link href={{ pathname: '/search', query: { q: 'react' } }}>Search</Link><Link> extends the HTML <a> tag with:
loading.tsx boundary)Control prefetching: <Link href="/heavy" prefetch={false}> disables automatic prefetch for heavy pages.
useRouter() HookFor programmatic navigation in event handlers (Client Components only):
'use client';
import { useRouter } from 'next/navigation';
function LoginButton() {
const router = useRouter();
async function handleLogin() {
await signIn();
router.push('/dashboard');
}
return <button onClick={handleLogin}>Login</button>;
}Key methods:
router.push('/path') — Navigate to a new route (adds to history)router.replace('/path') — Navigate without adding to history (login → dashboard)router.back() — Go back in historyrouter.forward() — Go forward in historyrouter.refresh() — Re-fetch the current route's Server Component data without a full page reloadrouter.prefetch('/path') — Manually prefetch a routeImportant: Import useRouter from next/navigation (App Router), not next/router (Pages Router).
redirect() FunctionFor server-side redirects in Server Components, Server Actions, and Route Handlers:
import { redirect } from 'next/navigation';
async function Profile() {
const session = await getSession();
if (!session) redirect('/login'); // Server-side redirect
return <Dashboard user={session.user} />;
}redirect() throws a special error internally — it cannot be wrapped in try/catch. It sends a 307 (temporary redirect) by default; use permanentRedirect() for 308 (permanent).
usePathname() and useSearchParams()Hooks for reading the current URL in Client Components:
'use client';
import { usePathname, useSearchParams } from 'next/navigation';
function NavLink({ href, children }) {
const pathname = usePathname();
const isActive = pathname === href;
return <Link href={href} className={isActive ? 'active' : ''}>{children}</Link>;
}useSearchParams() returns URLSearchParams for reading query string values. Wrap components using useSearchParams in <Suspense> to prevent the entire page from becoming dynamic.
Next.js navigation is a client-side transition that:
Shared layouts don't re-render during navigation — only the changed page segments update. This makes navigation feel instant.
<Link> for declarative navigation with automatic prefetching. useRouter() for programmatic navigation in event handlers. redirect() for server-side redirects in Server Components. Navigation is client-side — shared layouts are preserved, only changed segments re-render. Use usePathname() for active link styling.
Fun Fact
Next.js <Link> component originally required an <a> tag as a child: <Link href='/about'><a>About</a></Link>. This verbose pattern was one of the most common complaints from developers. Next.js 13 finally simplified it — <Link> now renders an <a> tag automatically, matching the HTML you'd expect to write.