How to preload vs prefetch vs preconnect: which resource hint for fonts
- Step 1Decide: is the font needed on THIS page, above the fold? — If yes, it's a `preload` candidate. Generate the tag with [the builder](/font-tools/preload-tag-builder) — paste the WOFF2 URL and it emits `<link rel="preload" as="font" type="font/woff2" href="..." crossorigin>`. Limit this to the 1–2 fonts on the LCP path.
- Step 2Decide: is the font needed on the NEXT likely page? — If the current page links heavily to a section that uses a different font (e.g. a docs font, an article serif), that's a `prefetch` candidate. Hand-write `<link rel="prefetch" as="font" type="font/woff2" href="..." crossorigin>`. The builder won't emit this — take a `preload` tag and change `preload` to `prefetch`.
- Step 3Decide: do your fonts live on a separate origin? — If fonts come from a different host than your HTML (a CDN, Google Fonts' `fonts.gstatic.com`, a separate asset domain), add `<link rel="preconnect" href="https://that-host" crossorigin>` so the handshake happens before the font request. Same-origin fonts need no preconnect.
- Step 4Combine correctly — preconnect THEN preload — For a cross-origin font you can name exactly, `preload` already implies the connection, so a separate `preconnect` to the same host is usually redundant. Use `preconnect` when you know the host but not yet the exact font URL (e.g. Google Fonts CSS will choose the font file).
- Step 5Add a dns-prefetch fallback for older browsers — `preconnect` isn't universally honoured; pairing `<link rel="dns-prefetch" href="https://that-host">` (no crossorigin) gives a cheaper DNS-only warm-up where preconnect isn't supported. Order dns-prefetch after preconnect.
- Step 6Measure, don't guess — Add the hint, re-run Lighthouse / WebPageTest, and check the waterfall: a working `preload` shows the font fetching early in parallel; a working `preconnect` shows the connection set up before the request; a wasteful `prefetch` shows bandwidth spent on a file the page never uses. Remove hints that don't move the needle.
The three hints at a glance
What each hint does, its priority, and the one-line font use case. crossorigin behaviour differs and is the most common source of silent failure.
| Hint | What it does | Priority | Downloads bytes? | Font use case |
|---|---|---|---|---|
rel="preload" | Fetch this exact URL now for the current page | High (fonts are high by default) | Yes — the full file | The 1–2 fonts on the current LCP path |
rel="prefetch" | Fetch this URL when idle for a future navigation | Lowest | Yes — into the cache | A font used on the next likely page, not this one |
rel="preconnect" | Open DNS + TCP + TLS to a host | n/a (connection only) | No | A cross-origin font CDN whose exact URL you don't know yet |
rel="dns-prefetch" | Resolve DNS for a host only | n/a | No | Cheap fallback to preconnect for a font host |
crossorigin requirement per hint
Fonts are CORS-fetched, so the crossorigin keyword matters differently for each hint. Get this wrong and the hint silently does nothing useful.
| Hint | crossorigin needed? | What happens if omitted |
|---|---|---|
preload (font) | Yes — always | Browser fetches the font twice; the preloaded copy is never matched to the @font-face fetch |
prefetch (font) | Yes — match the eventual fetch mode | Prefetched copy isn't reused by the CORS font fetch; bandwidth wasted |
preconnect (to a font origin) | Yes — fonts open a CORS connection | Browser warms a non-CORS connection; the actual CORS font request still pays for a new handshake |
dns-prefetch | No | DNS-only; crossorigin is irrelevant |
Does the JAD builder emit it?
The preload builder is a preload generator. Other hints are hand-written from the syntax in the cookbook.
| Tag | Generated by the builder? | How to get it |
|---|---|---|
rel="preload" for fonts | Yes | Paste URLs into the builder |
rel="prefetch" for fonts | No | Take a builder preload tag, change preload → prefetch |
rel="preconnect" | No | Hand-write per host (see cookbook) |
rel="dns-prefetch" | No | Hand-write per host |
Cookbook
Copy-pasteable hint blocks for the common font-delivery topologies. The preload lines come straight from the builder; the prefetch and preconnect lines you add by hand.
Self-hosted, single critical font (preload only)
ExampleSame-origin fonts need no preconnect — there's no cross-origin handshake to skip. Just preload the one critical WOFF2.
<!-- in <head>, before the stylesheet --> <link rel="preload" as="font" type="font/woff2" href="/fonts/inter-400.woff2" crossorigin>
Cross-origin CDN, known URL (preconnect + preload)
ExampleWhen the font lives on a separate host and you know the exact file, preconnect to the host AND preload the file. The preconnect is mostly belt-and-braces here since preload implies the connection, but it makes intent explicit and helps if the preload is discovered late.
<link rel="preconnect" href="https://cdn.example.com" crossorigin>
<link rel="preload" as="font" type="font/woff2"
href="https://cdn.example.com/fonts/brand.woff2" crossorigin>Google Fonts, URL not known yet (preconnect only)
ExampleWith the standard Google Fonts <link> the browser fetches the CSS first, then discovers the font URL. You can't preload a file you don't yet know, so preconnect to the font host so the eventual fetch is fast. Two hosts are involved: fonts.googleapis.com (the CSS) and fonts.gstatic.com (the files).
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Inter&display=swap">Next-page font (prefetch)
ExampleOn a landing page that links to a docs section using a different mono font, prefetch the mono WOFF2 so it's cached before the user clicks through. Start from a builder preload tag and swap the rel value.
<!-- builder gives you this preload: --> <link rel="preload" as="font" type="font/woff2" href="/fonts/jetbrains-mono.woff2" crossorigin> <!-- change preload -> prefetch for a next-page font: --> <link rel="prefetch" as="font" type="font/woff2" href="/fonts/jetbrains-mono.woff2" crossorigin>
dns-prefetch fallback for older browsers
ExamplePair preconnect with dns-prefetch so browsers that ignore preconnect still get a DNS head start. dns-prefetch takes no crossorigin.
<link rel="preconnect" href="https://cdn.example.com" crossorigin> <link rel="dns-prefetch" href="https://cdn.example.com">
Edge cases and what actually happens
Every row below was probed against the live API. Some documented requirements (alphabetical axis order, numerical tuple order) are not actually enforced in practice — useful to know if you've been blaming the wrong thing for a 400.
preload and prefetch on the same font URL
Redundant — preload winsPutting both on the same resource is pointless: preload already starts a high-priority fetch for this page, making the low-priority prefetch moot. Browsers won't double-download, but the prefetch line is dead weight and confuses the next maintainer. Pick one based on whether the font is current-page (preload) or next-page (prefetch).
preconnect to your own origin
No-op — wasted hintIf the fonts are same-origin (/fonts/... on the same host as the HTML), the browser is already connected — there's nothing to warm up. A preconnect to your own origin does nothing and just costs a parse. Reserve preconnect for genuinely separate hosts.
preconnect without crossorigin to a font host
Warm connection wastedFonts open a CORS (anonymous-credentials) connection. A preconnect without crossorigin warms a *different* connection (credentialed/normal), so the actual CORS font request still has to do its own handshake. For Google Fonts this is the classic gotcha: fonts.gstatic.com MUST have crossorigin on the preconnect; fonts.googleapis.com (CSS) does not.
prefetch on a slow connection
Can hurt — competes for bandwidthprefetch is lowest-priority, but on a constrained network it still competes with current-page resources. Prefetching a large font the user may never reach steals bytes from the page they're on now. Browsers deprioritise prefetches, so the impact is usually small — but avoid prefetching heavy fonts speculatively on mobile.
preload a URL that doesn't match the @font-face fetch
Warning — preloaded but not usedIf the preloaded URL differs from the font the page actually requests (path casing, trailing slash, a ?v= cache-buster on one but not the other, or a missing crossorigin), the browser fetches the font twice and logs preloaded ... but not used. The two requests must be byte-identical in URL and mode to be deduplicated.
preconnect cap — too many warm connections
Diminishing returnsEach preconnect holds open a socket and costs a TLS handshake up front. Chrome effectively limits how many it'll honour, and warming connections to hosts you don't use on the critical path wastes resources. Preconnect to the 1–2 font/asset hosts that matter, not every third-party domain.
prefetch ignored when the next navigation isn't predicted
By design — best-effort onlyprefetch is a hint, not a guarantee. Browsers may drop it under memory pressure, on Save-Data, or when they don't think the resource will be needed. Treat it as an optimisation that *might* land, never as a correctness mechanism — the next page must still work if the prefetch didn't happen.
The builder can't emit prefetch/preconnect for you
By design — preload-only toolThe JAD preload builder generates rel="preload" tags exclusively. There is no toggle for prefetch, preconnect, or dns-prefetch. Generate the preload tags, then hand-edit/append the other hints from the syntax above — they're one-liners.
Frequently asked questions
What's the one-line difference between preload and prefetch?
preload fetches a resource now, at high priority, for the page you're on. prefetch fetches a resource later, at the lowest priority, for a page the user will *probably* visit next. Same <link as="font"> shape, opposite timing and priority.
And preconnect?
preconnect downloads nothing. It opens the DNS lookup, TCP connection, and TLS handshake to a host so that when you *do* request a font from it, the expensive connection setup is already done. Use it for cross-origin font hosts.
Can the JAD builder generate prefetch or preconnect tags?
No — it emits rel="preload" tags only. For a next-page font, take a generated preload tag and change preload to prefetch. For a host warm-up, hand-write the preconnect. Both are single lines shown in the cookbook above.
Do I need preconnect if I'm already preloading the font?
Usually not. A cross-origin preload with the exact URL implies the connection setup, so a separate preconnect to the same host is mostly redundant. preconnect earns its keep when you know the *host* but not the exact *file* — e.g. with the standard Google Fonts CSS link, where the browser discovers the font URL only after fetching the CSS.
Why does fonts.gstatic.com need crossorigin on preconnect but fonts.googleapis.com doesn't?
fonts.gstatic.com serves the font files, which are fetched in CORS mode — the preconnect must match that mode, so it needs crossorigin. fonts.googleapis.com serves the CSS, fetched as a normal stylesheet (no CORS), so its preconnect has no crossorigin. Mismatching the mode warms the wrong connection.
Is preconnect ever wasteful?
Yes. Preconnecting to your own origin (same-origin fonts) is a no-op. Preconnecting to many third-party hosts holds open sockets and costs handshakes for connections you may not use on the critical path — Chrome limits how many it honours. Stick to the 1–2 hosts that matter.
Can I use preload and prefetch on the same font?
Don't. preload already starts the download; the prefetch becomes redundant. Choose based on the font's role: current-page-critical → preload; likely-next-page → prefetch.
Does prefetch hurt my current page's performance?
Slightly. It's the lowest priority and modern browsers deprioritise it, but on slow networks it still competes for bandwidth with current-page resources. Avoid speculatively prefetching large fonts on mobile or under Save-Data.
What's dns-prefetch and do I still need it?
dns-prefetch resolves a host's DNS only — cheaper and more widely honoured than preconnect, but it doesn't set up TCP/TLS. Pair it with preconnect as a fallback for browsers that ignore preconnect. It takes no crossorigin.
Which hint improves LCP the most for fonts?
preload on the LCP-element's font, on a cold-cache first visit — that's the high-leverage one (100–500 ms on slow connections). preconnect helps when the font is cross-origin and the connection setup is on the critical path. prefetch doesn't help the current page at all; it's purely a next-navigation optimisation. See the Core Web Vitals strategy guide.
Do these hints work for self-hosted Google Fonts?
If you self-host (recommended for privacy/perf), the fonts are same-origin: no preconnect needed, and you preload the specific WOFF2 directly. Generate the CSS with google-fonts-css-generator (or self-host the files), then preload the critical one. preconnect is only relevant while you're still loading fonts cross-origin from Google's CDN.
What attributes go on each hint?
preload/prefetch for fonts: as="font", type="font/woff2", href, crossorigin. preconnect/dns-prefetch: href (and crossorigin on preconnect to a font origin). The full attribute catalogue, including media and fetchpriority for preload, is in the attributes reference.
Privacy first
Every JAD Font tool runs entirely in your browser using opentype.js and the wawoff2 WASM Brotli encoder. Your fonts never leave your device — verified by zero outbound network requests during processing.