Fast navigation is a key Next.js benefit, and it depends on using Link and the navigation hooks correctly.
Use the `<Link>` component from next/link for internal navigation: <Link href="/blog">Blog</Link>. It renders an <a> but performs a client-side transition: only the changed segments are fetched and rendered, layouts keep their state, and the browser doesn't reload.
Prefetching: in production, links are prefetched when they enter the viewport or are hovered, so the next page is often ready before the click. How much is prefetched depends on the route; with Next.js 16's Partial Prefetching, the static App Shell of a route is prefetched by default. Pass prefetch={false} to disable it for rarely used links.
In Client Components, the hooks from next/navigation give you programmatic control:
useRouter()—router.push('/path'),router.replace,router.back(),router.refresh()(re-fetch server data for the current route).usePathname()— the current path, e.g. to highlight the active link.useSearchParams()— read query parameters.useParams()— dynamic route params.
On the server (Server Components, Server Actions, Route Handlers), call redirect('/login') from next/navigation. It throws a special error that the framework handles, so code after it doesn't run.
Plain <a> tags work but cause full page loads. External links can use <a> directly.
Example
// app/ui/nav-links.tsx
'use client'
import Link from 'next/link'
import { usePathname, useRouter } from 'next/navigation'
const links = [{ href: '/', label: 'Home' }, { href: '/blog', label: 'Blog' }, { href: '/about', label: 'About' }]
export function NavLinks() {
const pathname = usePathname() // e.g. "/blog"
const router = useRouter()
return (
<nav>
{links.map((l) => (
<Link key={l.href} href={l.href} className={pathname === l.href ? 'active' : ''}>
{l.label}
</Link>
))}
<button onClick={() => router.push('/search?q=next')}>Search</button>
</nav>
)
}Remember
<Link>does client-side transitions and prefetches in productionuseRouter,usePathname,useSearchParamscome fromnext/navigation(client only)- Use
redirect()on the server; it throws and stops execution
Watch out for
- Importing
useRouterfromnext/router(Pages Router) in an App Router component; usenext/navigation.