Your <Link> is firing 200 requests
Next.js prefetches every link in the viewport by default. On a list page, that's hundreds of requests before the user clicks anything.
The default behavior nobody warns you about
Open any Next.js app with a list of links — a blog index, a product catalog, a dashboard sidebar. Open your browser's Network tab. Watch the requests pile up.
Every <Link> that enters the viewport triggers a prefetch. On a page showing 40 blog posts, that's 40 prefetch requests firing the moment the page loads. If those are SSR routes, you just triggered 40 server-side renders.
If they're static, you loaded 40 route bundles. Either way, the user hasn't clicked anything yet.
The concept of a prefetch budget
Think of prefetching like a budget: you have a limited number of requests you should fire proactively. A good rule of thumb: no more than 5-10 prefetches per page. That means your primary navigation links and the 1-2 most likely next actions.
Everything else should load on demand. Here's the math: 1M monthly visitors × 40 prefetches per page view = 40M extra requests. At Vercel's $2 per 1M overage requests, that's $80/month in prefetch requests alone — for pages nobody clicked.
How to disable default prefetching
The fix is simple: add prefetch={false} to all your <Link> components. This is what HostCost does on every single link. Navigation links, feature cards, guide lists — all use prefetch={false}.
The user experience impact is minimal. Modern browsers are fast enough that a route loads in ~100-200ms on click, which feels instant. The alternative — prefetching everything — wastes bandwidth, burns through request quotas, and can actually make the current page slower by competing for network resources.
Smart prefetching: hover with debounce
If you want the best of both worlds: prefetch on hover intent. When a user hovers over a link for 100-200ms, trigger a prefetch. This catches 80% of navigation intentions with a fraction of the requests.
You can implement this with a simple onMouseEnter handler and a timeout. Most users hover for at least 200ms before clicking, which gives you enough time to prefetch the route. Combine this with prefetch={false} on the Link, and you get responsive navigation without the request flood.
Bundle size × millions of users = money
Prefetching doesn't just mean server requests — it also means downloading JavaScript bundles. Each prefetched route downloads its JS chunk. On a slow connection, prefetching 40 route bundles can actually make the current page feel sluggish because the browser is busy downloading code for pages the user might never visit.
This is doubly wasteful: you're paying for bandwidth (both CDN egress and the user's data plan), and you're degrading the current page's performance. React.lazy() and dynamic imports help — but only if you're not prefetching everything anyway.
External links don't need the router
Here's a subtlety most devs miss: Next.js <Link> is designed for internal routes. Wrapping an external URL (https://example.com) in <Link> gives you zero benefit. With prefetch={true} (the default), Next.js will attempt to prefetch the external destination — a wasted cross-origin request that always fails.
Even with prefetch={false}, <Link> intercepts the click event, runs it through the router, and parses the URL before realizing it's external and falling back to a normal navigation. That's unnecessary JavaScript execution for every click. On a page with a blogroll, resource list, or references section, this adds up fast.
Twenty external <Link> components = twenty wasted prefetch attempts on page load. The fix: use plain <a target="_blank" rel="noopener noreferrer"> for any URL that leaves your domain. Reserve <Link> for internal routes where client-side navigation actually matters.
The HostCost approach
Every internal Link on this site uses prefetch={false}. Every external link uses a plain <a> tag. We chose every link type deliberately: <Link prefetch={false}> for internal routes (client-side navigation without prefetch waste), plain <a> for external URLs (zero router overhead, zero prefetch leaks).
The result: zero wasted requests, lower bandwidth costs, and no observable UX penalty. If your site has fewer than 20 links on a page, you might not notice the cost of default prefetching. But if you're building a list-heavy app — e-commerce, blog, documentation, dashboard — turn it off, use the right tag for the right link, and measure the difference.
Your hosting bill will thank you.
Want to see these principles in action?