next/link and client-side navigation
Link has appeared in every part of this series that links between routes, without ever covering what it does beyond rendering an <a> tag. This part is that explanation — prefetching specifically, since it's the part that isn't visible just from reading the code.
What happens on hover
import Link from "next/link";
<Link href="/posts/hello-app-router">Read this post</Link>By default, Link prefetches the linked route's data in the background as soon as it scrolls into the viewport (and again, more eagerly, when it's actually hovered or focused) — by the time a click actually happens, the page it's navigating to has often already been fetched. Combined with client-side routing (no full page reload — the browser doesn't re-request the whole document, just swaps in the new route's content), this is what makes App Router navigation feel close to instant for a route that's already been prefetched.
Turning prefetching off
<Link href="/posts/hello-app-router" prefetch={false}>
Read this post
</Link>Prefetching every link on a very large listing page — hundreds of posts — means hundreds of background requests most visitors will never actually click through to. prefetch={false} opts a specific link out, worth doing deliberately on a page with an unusually large number of links rather than as a default habit.
When a plain anchor tag is still correct
<a href="https://github.com/vercel/next.js" target="_blank" rel="noopener noreferrer">
Next.js on GitHub
</a>Link is built for internal navigation within the same Next.js app — prefetching and client-side routing only make sense for routes the app itself controls. An external link, like the one above, gets no benefit from Link at all and should stay a plain <a> tag; using Link for it doesn't break anything, it just adds nothing.
Active link styling
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
export function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
const pathname = usePathname();
const isActive = pathname === href;
return (
<Link href={href} className={isActive ? "active" : undefined}>
{children}
</Link>
);
}usePathname() only works in a Client Component — it's a hook reading live browser navigation state, the same category of client-only API useState was in part 3 — which is why this needs its own small "use client" component rather than living directly in the (Server Component) root layout from part 4.
Reaching for router.push() inside a click handler to navigate somewhere a plain Link would work fine. Link gets prefetching and is crawlable by search engines (a real href in the rendered HTML) for free — an imperative router.push() call is the right tool for navigating after something happens (a successful form submission, covered starting part 14), not as a substitute for a link a person can see and click directly.
The blog's reading experience and SEO layer are both solid now. Next: giving the blog a real backend operation — a Route Handler, Next.js's way of building an actual API endpoint.