Self-host web fonts on Shopify CDN
When a typeface isn't available in the Shopify font library, self-host it on the Shopify CDN instead of loading it from an external service such as Google Fonts. This eliminates connection overhead and multiple requests.
Self-hosting fonts eliminates external domain connections, uses automatic Shopify CDN delivery, provides automatic version cache busting through asset_url, enables faster font discovery and download, works with Early Hints through Liquid filters, and removes one external dependency.
- Self-hosted fonts: eliminate external connections. Fastest approach.
- Optimized Google Fonts: reduces connection overhead with
preconnectand async loading. - Unoptimized Google Fonts: multiple separate connections. Slowest approach.
Anchor to When to self-hostWhen to self-host
If the typeface you need is in the Shopify font library, then reach for a font_picker setting with the font_face and font_url filters first. Those filters serve the font from the Shopify CDN, normally under /cdn/fonts/ on the domain that served the page, so they avoid the external connection for the same reason self-hosting does. They also let merchants change the font in the theme editor without a code change, and they cover the bold and italic variants through font_modify. Shopify's own themes, including Dawn, use this approach.
Self-host when the font filters can't do the job:
- The typeface isn't in the Shopify font library, such as a licensed brand font.
- You need a subset, variable axis, or Unicode range that the library's files don't cover.
- The typeface is fixed by brand guidelines, so it shouldn't be a merchant-editable setting.
If none of those apply, then the font filters are the lower-maintenance option and reach the same result.
Anchor to Step 1: Download font filesStep 1: Download font files
Use Google Webfonts Helper to download Google Fonts. This tool provides WOFF2 and WOFF files for modern browsers, and CSS snippets ready to use. You need WOFF2 as the primary format for best compression, and WOFF as the fallback for older browsers. Skip EOT, TTF, and SVG, because modern browsers don't need them.
Anchor to Step 2: Add fonts to theme assetsStep 2: Add fonts to theme assets
Place downloaded font files in the /assets directory:
Anchor to Step 3: Define ,[object Object], with ,[object Object]Step 3: Define @font-face with asset_url
@font-face with asset_urlCreate inline styles in your layout file, such as theme.liquid, or in a .css.liquid file:
layout/theme.liquid
Defining fonts inline in the <head> ensures that they're discovered immediately, which is faster than loading an external CSS file first. The asset_url filter provides automatic cache busting through version numbers.
Anchor to Step 4: Use the fontStep 4: Use the font
Reference the font family in your CSS:
Always provide fallback fonts in case the web font fails to load.
Anchor to Step 5: Preload critical fontsStep 5: Preload critical fonts
For fonts used for content visible in the initial viewport, preload them for faster rendering:
Font preloads must be CORS-enabled, even for same-origin fonts. Don't pass crossorigin to preload_tag: it emits crossorigin="anonymous" on its own when as is font.
Font preloads must be CORS-enabled, even for same-origin fonts. Don't pass crossorigin to preload_tag: it emits crossorigin="anonymous" on its own when as is font.
Anchor to Alternative: ,[object Object], fileAlternative: .css.liquid file
.css.liquid fileIf you prefer to keep @font-face declarations in a CSS file, then create assets/fonts.css.liquid:
assets/fonts.css.liquid
Include in theme.liquid:
The source file must have a .css.liquid extension for Shopify to process the Liquid code inside it. Reference it as fonts.css, without the .liquid extension: Shopify serves the compiled asset under that name.
Anchor to Self-hosting best practicesSelf-hosting best practices
Always use font-display: swap to avoid invisible text while fonts load:
This prevents FOIT (Flash of Invisible Text) and lets customers see content immediately with a fallback font.
Limit the number of fonts. Each font family and weight requires a separate download. 1 to 2 font families is good, 2 to 4 weights per family is reasonable, and more than 6 total font files impacts performance.
Don't forget fallback fonts. See Reduce CLS from font swapping for information on reducing CLS from font swapping by customizing fallback fonts to match web font dimensions.
Anchor to ExamplesExamples
Anchor to When self-hosting isn't possibleWhen self-hosting isn't possible
Some font services don't allow self-hosting because of licensing restrictions. If you can't self-host, then add preconnect hints to warm up the connection early and minimize latency.
Anchor to Adobe TypekitAdobe Typekit
Typekit fonts can't be self-hosted. Add preconnect for both Typekit domains:
Anchor to Google FontsGoogle Fonts
Sometimes you must use the Google Fonts API directly because of dynamic font pickers or client requirements. If you can't self-host, then minimize the performance impact:
- Make the stylesheet async:
- Add
preconnect:
- Limit font weights.
Load only the weights you actually use. Good: ?family=Roboto:wght@400;700. Anti-pattern: ?family=Roboto:wght@100;200;300;400;500;600;700;800;900.
Anchor to TestingTesting
- Chrome DevTools Network panel: count connections to font domains. The count should be zero for self-hosted fonts.
- Network tab: verify that fonts load from
cdn.shopify.comor your store domain. - Compare timings: self-hosting eliminates external domain connections. Check the waterfall for fewer DNS and connection bars.
Anchor to ReferencesReferences
asset_urlfilterpreload_tagfilterfont_facefilterfont_pickersetting- Google Webfonts Helper
- Shopify fonts architecture
- MDN: font-display
- Reduce CLS from font swapping
- Use system fonts
- Serve assets from Shopify CDN