next/link renders a real <a> element — it has since Next.js 13 10,514 , when the nested <a> child was dropped — so middle-click, Ctrl-click and crawler discovery keep working. It adds a click handler that cancels the browser's navigation and hands the work to the router, plus an IntersectionObserver that prefetches the destination while the link is on screen.
import Link from 'next/link'
export default function Home() {
return <ul>
<li><Link href="/reports">Reports</Link></li>
<li><Link href="/dashboard" prefetch={false}>Dashboard (no prefetch)</Link></li>
</ul>
}The root layout adds a nav bar and a Clock, a Client Component counting seconds with setInterval, which answers the question this section turns on: does a navigation throw the page away? Clicking the Reports link in Chrome 1 produced one network request and left the clock running.
3086ms rsc /reports?_rsc=O7B9SOatjc8aCNiq rsc=1 prefetch=- clock before click : layout alive for 5s clock after click : layout alive for 7s
No document, no stylesheet, no bundle — one GET carrying the header rsc: 1, which asks for the React 7,897 Server Component payload of the part of the tree that changed. Swap that <Link> for a plain <a href="/reports"> and the same click costs a document, every asset in the <head>, a new React root and a clock that restarts at zero.
Four props change how the click behaves.
| Prop | Default | Effect |
|---|---|---|
| replace | false | Replaces the history entry instead of pushing one |
| scroll | true | Scrolls to the page element if it is off screen |
| prefetch | null | false disables it; see Prefetching |
| onNavigate | none | Runs only on same-origin client-side navigations |
scroll deserves care. The default is not "jump to the top": the router keeps the scroll position while the new page element is still in the viewport, and skips sticky and fixed elements when hunting for a scroll target, so content can land behind a sticky header. The fix is CSS — html { scroll-padding-top: 64px; }. onNavigate fires only when the router will handle the click, which makes it the place for an unsaved-changes prompt: e.preventDefault() on its event cancels the navigation, while a Ctrl-click, an external URL and a download link bypass it.