How to google fonts cdn vs self-hosted performance comparison
- Step 1Baseline the CDN version in DevTools — Open Chrome DevTools → Network, set throttling to Slow 4G, hard-reload the page that uses Google Fonts. Filter to `gstatic.com` and read the timing breakdown on the WOFF2 request: DNS lookup, Initial connection (TCP), SSL (TLS). On a cold connection this overhead is usually 100–400 ms before any font bytes transfer.
- Step 2Generate the self-hosted CSS — In the generator above, type your families (e.g. `Inter:wght@400;700`) into the **Families** field, leave font-display on `swap`, and click Generate. Download `google-fonts-self-hosted.css` and run the embedded curl script to pull the WOFF2 into `./woff2/`.
- Step 3Deploy and add a preload for the critical weight — Serve the CSS and WOFF2 from your origin. For the weight that renders your LCP text, add `<link rel="preload" as="font" type="font/woff2" crossorigin>` (build it with [the preload tag builder](/font-tools/preload-tag-builder)) so the browser fetches it on the warm connection before CSS finishes parsing.
- Step 4Re-measure the same request — Hard-reload again on Slow 4G. The `gstatic.com` rows are gone; the WOFF2 now appears under your own origin with no separate DNS/TLS line, because it rides the connection your HTML opened. Compare the Network waterfall side by side.
- Step 5Check Core Web Vitals before and after — Run Lighthouse (or compare field data in CrUX / Search Console) before and after. Watch LCP specifically when your hero text is a web font, and watch the 'Reduce the impact of third-party code' and 'Avoid chaining critical requests' audits, which both improve when Google's two origins disappear from the chain.
- Step 6Decide whether your origin is actually fast enough — Self-hosting only wins if your origin/CDN is reasonably fast. If your HTML TTFB is already 800 ms+ on a slow shared host, Google's edge may serve fonts faster than your origin — but the right fix is a better CDN for everything, not keeping the cross-origin font penalty. See the edge cases for the honest CDN-wins scenario.
Cost model: CDN vs self-hosted, cold connection
Qualitative breakdown of where the time goes on a first (cold) page load. Self-hosting removes the third-party connection setup; it does not change the WOFF2 download size itself.
| Cost component | Google Fonts CDN | Self-hosted on your origin |
|---|---|---|
| Extra DNS lookup | Yes — fonts.googleapis.com and fonts.gstatic.com (two hostnames) | None — same hostname as your HTML |
| Extra TLS handshake | Yes — new origin(s), full handshake on the critical path | None — reuses the open HTTP/2 connection |
| CSS round-trip before font | Yes — css2 request, then the gstatic font request | Font URL is already in your bundled CSS |
| Cross-site cache reuse | None since Chrome partitioned cache by site (Oct 2020) | None (same as CDN — no longer a CDN advantage) |
| WOFF2 byte size | Identical — same files | Identical — same files, served by you |
The cache-partitioning timeline
The single biggest reason the 'shared Google Fonts cache' argument is obsolete. After partitioning, the browser keys cached resources by the top-level site, so a font fetched on site A is never reused on site B.
| Browser | Cache partitioned by site since | Effect on shared font cache |
|---|---|---|
| Chrome / Edge (Chromium) | Chrome 86, October 2020 | Shared cross-site font cache eliminated |
| Firefox | Firefox 85, January 2021 (Network Partitioning) | Shared cross-site font cache eliminated |
| Safari | Partitioned cache since 2013, tightened over time | Never had meaningful cross-site sharing for years |
When to self-host vs keep the CDN
A decision matrix. Self-hosting is the default recommendation in 2026; the CDN only wins in one specific situation.
| Your situation | Recommendation | Why |
|---|---|---|
| Origin on a real CDN (Cloudflare, Vercel, Netlify, Fastly) | Self-host | Connection reuse beats a cold third-party handshake; no cache benefit lost |
| GDPR / privacy requirement | Self-host | Removes the visitor-IP transfer to Google entirely |
| Origin on a slow shared host, no CDN | Fix the origin first; CDN is a stopgap | Google's edge may genuinely serve fonts faster than a slow origin |
| Throwaway prototype / internal tool | CDN is fine | The connection cost doesn't matter when nobody's measuring CWV |
Cookbook
Measurement recipes and the decision logic, not invented millisecond figures — your numbers depend on your CDN, network, and font choices. For the privacy rationale that often co-justifies the switch see the GDPR self-hosting guide; to roll it out on a live site without downtime see the marketing-site migration.
Read the cross-origin cost in DevTools
ExampleThe numbers that matter are on the gstatic.com WOFF2 request's timing tab. DNS + Initial connection + SSL is the penalty self-hosting removes.
DevTools → Network → click the gstatic.com .woff2 request → Timing: Queueing .... DNS Lookup XX ms <- gone when self-hosted Initial connection XX ms <- gone when self-hosted SSL XX ms <- gone when self-hosted Request sent / TTFB .... Content Download .... (same bytes either way)
Generate the self-hosted equivalent
ExampleOne step replaces the two Google origins with your own. Type families, click Generate, download the CSS, run the curl script.
Families: Inter:wght@400;700
font-display: swap
→ google-fonts-self-hosted.css
src: url("./woff2/<hash>.woff2") format('woff2');
(plus a curl script that downloads each WOFF2)Drop the now-useless preconnect hints
ExampleSites add these for the Google CDN. After self-hosting they connect to origins you no longer use — delete them so the browser's early-connection budget goes to your own resources.
Before (remove these after migrating):
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
After — preload your own critical font instead:
<link rel="preload" href="/fonts/woff2/<hash>.woff2"
as="font" type="font/woff2" crossorigin>Lighthouse audits that move
ExampleThese are the audits where removing Google's two origins shows up. LCP improvement is largest when hero text uses the web font.
Improves after self-hosting: - 'Reduce the impact of third-party code' - 'Avoid chaining critical requests' (css2 -> gstatic chain removed) - 'Preconnect to required origins' (no third-party origins left) - LCP (warm-connection font fetch) Unchanged: - Total font bytes (same WOFF2 files)
The honest CDN-wins test
ExampleBefore assuming self-hosting is faster, confirm your origin actually is. Compare TTFB of your origin against Google's edge from a few regions.
# Compare origin TTFB vs Google edge from your target regions
curl -w 'origin TTFB: %{time_starttransfer}s\n' -o /dev/null -s \
https://your-site.com/fonts/woff2/<hash>.woff2
curl -w 'gstatic TTFB: %{time_starttransfer}s\n' -o /dev/null -s \
https://fonts.gstatic.com/s/inter/.../<hash>.woff2
# If gstatic is consistently faster, fix your CDN — don't keep the cross-origin penalty.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.
Slow origin with no CDN — the one case the CDN wins
CDN winsIf your HTML is served from a slow shared host with no edge network, Google's globally-distributed CDN can genuinely deliver fonts faster than your origin, even after paying the cross-origin connection cost. This is real — but the fix is to put your whole site on a proper CDN, which then makes self-hosting the faster option for fonts too. Don't use the CDN as a permanent crutch for a slow origin.
Expecting a shared cross-site cache speedup
No longer existsThe classic CDN argument — 'lots of sites use Google Fonts, so the font is already cached' — stopped working when Chrome partitioned the HTTP cache by top-level site in October 2020 (Firefox Jan 2021). Today every site downloads its own copy of every WOFF2 no matter who hosts it. Self-hosting loses nothing here.
Self-hosting all subsets, then measuring total bytes
ExpectedThe generator downloads every script subset Google offers (latin, latin-ext, cyrillic, greek, vietnamese, …). That doesn't change runtime bytes — browsers fetch only the unicode-range subsets a page uses — but a naïve 'total file size in /woff2/' looks larger. Measure what the browser actually downloads in the Network tab, not the folder size. To physically shrink the files, subset with the font subsetter.
Forgetting to preload after self-hosting
Slower than it should beSelf-hosting removes the third-party penalty but the font still isn't discovered until the CSS is parsed. For LCP-critical text, add a <link rel="preload" as="font" crossorigin> so the fetch starts immediately. Without it you've fixed the connection cost but not the discovery latency — build the tags with the preload tag builder.
crossorigin attribute mismatch on preload
Double fetchFonts are always fetched in CORS mode, so a <link rel="preload" as="font"> without crossorigin doesn't match the actual @font-face request and the browser fetches the file twice — worse than not preloading. Always include the crossorigin attribute on font preloads, even for same-origin self-hosted files.
Stale preconnect to gstatic still in the head
Wasted connectionMany sites have <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>. After self-hosting that origin is never used, so the browser opens a connection it'll never need — wasting part of its small early-connection budget. Remove both Google preconnect hints when you migrate.
font-display: block hides LCP text during download
Hurts LCPIndependent of CDN vs self-hosted: font-display: block keeps text invisible for up to ~3s while the font loads, which directly delays LCP if that text is your largest element. The generator defaults to swap; keep it for body/hero text. Choose deliberately with the font-display strategy tool.
Comparing variable vs static weight payloads
By designA single variable WOFF2 covering wght@100..900 is roughly the size of two static weights but gives you every weight in between. If you only ship two weights, two static files can be smaller than the variable file; if you use three or more weights, the variable file usually wins. This trade-off is identical whether you self-host or use the CDN — self-hosting doesn't change the bytes.
HTTP/1.1 origin negates connection reuse
Reduced benefitThe connection-reuse win assumes your origin speaks HTTP/2 (or HTTP/3), which multiplexes the font request over the existing connection. On a legacy HTTP/1.1 origin the browser may open a parallel connection anyway, eroding part of the advantage. Any modern CDN serves HTTP/2+ by default; confirm yours does.
Measuring on a warm (repeat) load
MisleadingOn a repeat visit the WOFF2 is in the browser cache and neither CDN nor self-hosted pays a download cost, so the two look identical. The difference shows up on the cold first load, which is what new visitors and search-engine crawlers experience. Always test with cache disabled / hard reload to see the real gap.
Frequently asked questions
Is self-hosting actually faster than Google's CDN?
On a cold first load, almost always yes if your origin is on a competent CDN. Using Google forces an extra DNS lookup and TLS handshake to fonts.googleapis.com and fonts.gstatic.com on the critical path before any font byte arrives; self-hosting rides the HTTP/2 connection your HTML already opened. The exact saving depends on your network and CDN — measure the DNS + connection + SSL timing on the gstatic request in DevTools to see your number. The WOFF2 download itself is the same bytes either way.
Doesn't Google have edge servers everywhere?
Yes — but so do Cloudflare, Fastly, Vercel, and Netlify. Geographic distance isn't the bottleneck; the cold-connection overhead of a separate origin is. Reusing the connection your HTML opened beats opening a fresh one to Google's edge, no matter how close that edge is. The only exception is a slow origin with no CDN at all (see the edge cases).
What about the shared Google Fonts cache?
It's gone. Chrome partitioned the HTTP cache by top-level site in version 86 (October 2020), and Firefox did the same in version 85 (January 2021). A font downloaded on one site is no longer reused on another. So the historical 'it's probably already cached' argument for the CDN no longer holds — every site downloads its own copy regardless of host. Self-hosting loses nothing here and removes the connection cost.
Is there any case where Google's CDN is genuinely faster?
One: when your own origin is slow and has no CDN. Google's global edge can then serve fonts faster than your origin even after the cross-origin penalty. But the correct fix is to put your site on a real CDN — which makes self-hosting faster for fonts too. Keeping the CDN just to paper over a slow origin trades a permanent third-party privacy and performance cost for a temporary patch.
Does self-hosting help SEO?
Indirectly. Core Web Vitals (LCP in particular) are a page-experience ranking signal, and self-hosting tends to improve LCP on cold loads by removing the third-party font connection from the critical path. Reducing third-party requests also generally lifts Lighthouse scores. It's not a direct ranking lever, but the CWV improvement is real and measurable.
How do I generate the self-hosted CSS?
Use the generator above: type your families (e.g. Inter:wght@400;700) into the Families field, choose a font-display value, and click Generate. It fetches Google's CSS, rewrites every gstatic.com URL to a relative ./woff2/ path, and appends a bash curl script that downloads each WOFF2. Download the .css, run the script, deploy both from your origin. It's free-tier and uploads nothing.
Will self-hosting change my font rendering?
No. The WOFF2 files are byte-identical to what Google serves — self-hosting just changes where they're fetched from. Rendering, kerning, ligatures, and variable axes are all preserved. If you want pixel-level proof, run visual-regression snapshots (Percy, Chromatic, Playwright) before and after; the migration guide covers that workflow.
Should I still preload fonts after self-hosting?
Yes — for the LCP-critical weight. Self-hosting fixes the connection cost but the font still isn't discovered until CSS is parsed. A <link rel="preload" as="font" type="font/woff2" crossorigin> starts the fetch earlier on the warm connection. Build the tags with the preload tag builder. Don't preload every weight — only the one or two on the critical path, or you'll delay other resources.
Does variable vs static affect the CDN-vs-self-host decision?
No — both serve the same files. A variable WOFF2 is roughly two static weights' size but covers every weight; pick variable when you use three or more weights, static when you use one or two. The choice affects total bytes, not whether self-hosting is faster. Self-hosting wins on connection cost regardless of which font format you request.
Do I need to keep the Google preconnect hints?
No — delete them. <link rel="preconnect" href="https://fonts.googleapis.com"> and the fonts.gstatic.com one point at origins you no longer use after self-hosting, so they waste part of the browser's limited early-connection budget. Remove both and, if anything, add a preload for your own critical font file instead.
How do I prove the improvement to stakeholders?
Capture a DevTools Network waterfall and a Lighthouse report before and after on Slow 4G with cache disabled. Show the gstatic.com DNS/connection/SSL rows disappearing and the LCP and 'third-party code' audit deltas. For field data, compare CrUX / Search Console CWV over the weeks after deploy. The migration guide folds this into a before/after case-study workflow.
Is the performance win worth the maintenance?
For a production site with measured CWV goals, yes — it's a one-time generate-and-commit, and you only re-run when you change weights or families. The fonts are pinned in your repo, so there's no ongoing per-deploy cost. For a throwaway prototype where nobody measures performance, the CDN's zero-setup convenience is fine. The privacy angle (see the GDPR guide) often tips even small sites toward self-hosting.
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.