preload, prefetch, preconnect, dns-prefetch — what's the difference?
preload = high-priority current-page resource. prefetch = low-priority future-navigation resource. preconnect = warm up TCP+TLS to an origin. dns-prefetch = resolve DNS only. Use the right one or you waste bandwidth.
Resource hints tell the browser to do work earlier than it otherwise would. Each has a precise purpose; mixing them up wastes bandwidth or slows the page.
<link rel="preload"> — fetch this NOW for the current page.
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>High priority. The browser fetches the resource immediately, in parallel with HTML parsing, but doesn't use it until the parser hits the actual reference. Saves a round-trip on resources discovered late (CSS-referenced fonts, JS-loaded chunks).
The as attribute is required — it sets priority and lets the browser apply the right Accept header / CORS rules. Without it, the resource may be downloaded twice.
<link rel="modulepreload"> — same as preload, but for JS modules. Resolves and parses dependency graphs ahead of time. Use for ES modules; as="script" works too but modulepreload is more correct.
<link rel="prefetch"> — fetch this for a LIKELY next navigation.
<link rel="prefetch" href="/dashboard.js">Low priority. Browser fetches when idle. Cached for use on the next page. Used by Next.js (<Link prefetch> defaults to true) and Nuxt to make hover-or-near-visible links instant. Bandwidth-aware — Chrome respects "data saver" mode.
<link rel="preconnect"> — open TCP + TLS to an origin NOW.
<link rel="preconnect" href="https://cdn.example.com" crossorigin>Saves DNS lookup + TCP handshake + TLS negotiation (typically 100–300ms). Apply to origins you'll definitely hit (CDN, image host, analytics). Limit to ~4 — each preconnect costs a TCP connection.
The crossorigin attribute is needed for fonts and other CORS-required resources; otherwise the browser opens an anonymous connection that won't be reused for the credentialed request.
<link rel="dns-prefetch"> — resolve DNS only.
<link rel="dns-prefetch" href="https://maybe-needed.com">Cheaper than preconnect (no TCP/TLS). Right for "we might hit this origin." Often used as a fallback for browsers that don't support preconnect.
<link rel="prerender"> — historical; deprecated in most browsers. Replaced by the Speculation Rules API (Chromium):
<script type="speculationrules">
{ "prerender": [{ "where": { "selector_matches": "a[href^='/products/']" }, "eagerness": "moderate" }] }
</script>Renders the next page in a hidden tab so navigation is instant. Powerful but risky — analytics fire, side effects run. Use only for safe GET pages.
<link rel="preload" as="image" imagesrcset> — for responsive image hero (LCP optimization):
<link rel="preload" as="image" imagesrcset="/hero-mobile.webp 600w, /hero-desktop.webp 1600w" imagesizes="100vw">Tells the browser to start the LCP image fetch before the parser sees the <img>.
Decision tree.
- Need this resource for the current page, browser doesn't see it early? → preload.
- Likely next page resource? → prefetch.
- Will hit a third-party origin soon? → preconnect (or dns-prefetch if uncertain).
- Want to fully render the next page in advance? → Speculation Rules API.
Common mistakes.
- Preloading everything → priority inversion, browser starves visible resources to fetch hints.
- Forgetting
ason preload → resource fetched twice. - Forgetting
crossoriginon font preload → fetched twice (anonymous + credentialed). - Preloading large JS chunks the user never needs → wasted bandwidth, hurts metered users.
Measure. DevTools Network panel shows the priority and timing. Lighthouse flags wasted preloads ("Preload requests are not used within a few seconds").
Code
Follow-up questions
- •Why does font preload need crossorigin?
- •When would you choose dns-prefetch over preconnect?
- •How does Next.js Link's prefetch behavior work?
- •What's the Speculation Rules API replacing?
Common mistakes
- •Omitting `as` on preload — resource fetched twice.
- •Preloading too much — priority inversion, browser starves real work.
- •Using prefetch for current-page resources — too low priority.
- •Preconnect to many origins — each costs a TCP connection.
Performance considerations
- •preload + fetchpriority='high' is the strongest signal for LCP images.
- •preconnect saves up to 300ms per third-party origin on slow networks.
- •Lighthouse 'wasted preload' audit catches misuses.
Edge cases
- •Mobile browsers may ignore prefetch under 'data saver' mode.
- •Cross-origin font preload without crossorigin → cache miss when the actual font request comes in.
- •Speculation Rules API has UA support; degrade gracefully.
Real-world examples
- •Next.js prefetches linked routes on hover/visibility. Stripe Elements preconnects to api.stripe.com on page load.