How to Add Custom Fonts in Shopify Using Preload and Liquid
When you’re building or customizing a Shopify theme, adding custom fonts can be a key factor in achieving the desired look and feel of the store. However, simply adding fonts isn’t always enough—if they load slowly, it can negatively impact the user experience. One way to improve performance is by preloading fonts and using Liquid for efficient font management.
In this post, I’ll show you how to properly add custom fonts to a Shopify theme, explain why preloading fonts is crucial for performance, and why it’s best to organize font-loading logic in a Liquid file for cleaner, maintainable code.
Code Example & Explanation
Step 1: Preloading Fonts in theme.liquid
To ensure that custom fonts load quickly, we need to preload them in the theme.liquid file. Preloading tells the browser that a resource will be needed soon and should be fetched early, reducing the time it takes for the fonts to appear on the page.

Here’s the code I added to preload custom fonts:
<link rel='preconnect' href='https://cdn.shopify.com' crossorigin>
<!-- Bourbon Regular -->
<link rel='preload' as='font' href='{{ 'Bourbon-Regular.woff2' | asset_url }}' type='font/woff2' crossorigin>
<link rel='preload' as='font' href='{{ 'Bourbon-Regular.woff' | asset_url }}' type='font/woff' crossorigin>
<link rel='preload' as='font' href='{{ 'Bourbon-Regular.eot' | asset_url }}' type='font/eot' crossorigin>
<link rel='preload' as='font' href='{{ 'Bourbon-Regular.svg' | asset_url }}' type='font/svg' crossorigin>
<link rel='preload' as='font' href='{{ 'Bourbon-Regular.ttf' | asset_url }}' type='font/ttf' crossorigin>
<!-- SuisseIntl Regular -->
<link rel='preload' as='font' href='{{ 'SuisseIntl-Regular.woff2' | asset_url }}' type='font/woff2' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Regular.woff' | asset_url }}' type='font/woff' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Regular.eot' | asset_url }}' type='font/eot' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Regular.svg' | asset_url }}' type='font/svg' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Regular.ttf' | asset_url }}' type='font/ttf' crossorigin>
<!-- SuisseIntl Medium -->
<link rel='preload' as='font' href='{{ 'SuisseIntl-Medium.woff2' | asset_url }}' type='font/woff2' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Medium.woff' | asset_url }}' type='font/woff' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Medium.eot' | asset_url }}' type='font/eot' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Medium.svg' | asset_url }}' type='font/svg' crossorigin>
<link rel='preload' as='font' href='{{ 'SuisseIntl-Medium.ttf' | asset_url }}' type='font/ttf' crossorigin>Why Preloading Is Important
Preloading custom fonts ensures they are fetched early in the page load process, even before the CSS that calls them is fully parsed. This reduces the “flash of unstyled text” (FOUT) that happens when the browser temporarily displays fallback fonts while waiting for the custom font files to load.

Without preloading, the fonts may not be fetched until the browser reaches the CSS that references them. By then, the text may have already been displayed using the default system fonts, only to be re-rendered once the custom fonts load—this can create a jarring experience for users.
Step 2: Organizing Font Definitions in a Liquid Snippet
To keep the theme.liquid file clean and organized, I used a separate Liquid snippet (css-fonts.liquid) to define the @font-face rules for the custom fonts. This snippet makes the theme easier to maintain, as font-related changes are kept separate from the rest of the theme’s layout and logic.
Here’s an example of the font-face declarations inside css-fonts.liquid:
<style>
@font-face {
font-family: 'Bourbon Regular';
font-style: normal;
font-weight: 400;
font-display: block !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: antialiased;
src: local('Bourbon Regular'), local('Bourbon-Regular'),
url({{ 'Bourbon-Regular.woff2' | asset_url }}) format('woff2'),
url({{ 'Bourbon-Regular.woff' | asset_url }}) format('woff'),
url({{ 'Bourbon-Regular.eot' | asset_url }}) format('embedded-opentype'),
url({{ 'Bourbon-Regular.svg' | asset_url }}) format('svg'),
url({{ 'Bourbon-Regular.ttf' | asset_url }}) format('truetype');
}
/* SuisseIntl Regular */
@font-face {
font-family: 'SuisseIntl';
font-style: normal;
font-weight: 400;
font-display: block !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: antialiased;
src: local('SuisseIntl'), local('SuisseIntl'),
url({{ 'SuisseIntl-Regular.woff2' | asset_url }}) format('woff2'),
url({{ 'SuisseIntl-Regular.woff' | asset_url }}) format('woff'),
url({{ 'SuisseIntl-Regular.eot' | asset_url }}) format('embedded-opentype'),
url({{ 'SuisseIntl-Regular.svg' | asset_url }}) format('svg'),
url({{ 'SuisseIntl-Regular.ttf' | asset_url }}) format('truetype');
}
/* SuisseIntl Medium */
@font-face {
font-family: 'SuisseIntl';
font-style: normal;
font-weight: 500;
font-display: block !important;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: antialiased;
src: local('SuisseIntl'), local('SuisseIntl'),
url({{ 'SuisseIntl-Medium.woff2' | asset_url }}) format('woff2'),
url({{ 'SuisseIntl-Medium.woff' | asset_url }}) format('woff'),
url({{ 'SuisseIntl-Medium.eot' | asset_url }}) format('embedded-opentype'),
url({{ 'SuisseIntl-Medium.svg' | asset_url }}) format('svg'),
url({{ 'SuisseIntl-Medium.ttf' | asset_url }}) format('truetype');
}
</style>Why Use a Separate Liquid Snippet?
Using a snippet like this keeps your theme.liquid file lean, focusing on the overall structure of the page. It also makes the code more modular, allowing for easy updates to fonts without touching other core theme files. This method is especially helpful when you need to manage multiple custom fonts in your theme, as you can handle all font-related tasks in one file.
Best Practices for Loading Custom Fonts
- Use Multiple Font Formats:
Ensure you provide different formats (woff2,woff,eot,svg, andttf) to maximize browser compatibility. Modern browsers preferwoff2because it offers better compression and faster loading. - Preload Critical Fonts:
Only preload the fonts that are critical to the user’s first impression—usually the primary fonts used for headings and body text. Avoid preloading every font file, as this can lead to over-fetching resources. - Optimize Font Display:
Settingfont-display: block;helps prevent FOUT (Flash of Unstyled Text) by blocking the text rendering until the font is ready. You can adjust this value based on your preference (e.g.,swap,fallback), but blocking ensures a consistent look. - Test Font Performance:
After implementing custom fonts, always test the site’s performance using tools like Google Lighthouse or WebPageTest to ensure the fonts aren’t slowing down the site. Preloading should improve the load time if done correctly.
Common Mistakes to Avoid
- Over-preloading Fonts:
Preloading every font file in your theme is unnecessary and can lead to slower page loads due to fetching resources that aren’t immediately needed. Stick to preloading only the most critical fonts. - Neglecting Fallback Fonts:
Always include fallback fonts (likeArial,sans-serif) in your CSS font stack to provide a smooth user experience while the custom fonts load or in case they fail to load.
Bonus Tip: Converting Font Formats
If your custom fonts are not in all the formats that Shopify supports, you’ll need to convert them. There are many free online tools to help you do this. I recommend using AnyConv for converting fonts between formats such as woff, woff2, eot, ttf, and more. This will ensure maximum compatibility across browsers.
