---
title: Use preload resource hints sparingly
description: >-
  Use `<link rel="preload">` only for one or two critical resources the browser
  discovers late, because preloading too many resources interferes with the
  browser's own prioritization.
source_url:
  html: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-preload-resource-hints-sparingly
  md: >-
    https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-preload-resource-hints-sparingly.md
api_name: liquid
---

# Use preload resource hints sparingly

Use `<link rel="preload">` only for one or two critical resources that the browser would otherwise discover too late. Overusing `preload` degrades browser prioritization.

**Shopify already preloads your render-blocking resources:**

Shopify scans the rendered `<head>` on every storefront response and preloads up to 10 render-blocking scripts and stylesheets automatically, through `Link` headers that reach the browser before the HTML body. You don't need to preload those resources yourself, and doing so consumes a budget you'd rather spend elsewhere. See [Automatic preloads use the same budget](#automatic-preloads-use-the-same-budget).

***

## Why

`preload` tells the browser to download a resource immediately at a High priority. Preloading assets that are already in HTML provides no benefit, because the browser's preload scanner finds resources in HTML quickly. Preloading multiple resources degrades overall prioritization and can hurt metrics by delaying critical resources.

### Automatic preloads use the same budget

Shopify sends at most 10 preload `Link` headers per response, and the automatic render-blocking preloads are placed first. Your own hints fill the remaining slots in this order:

1. Automatic render-blocking preloads, derived from the rendered `<head>`.
2. Stylesheet preloads, from `stylesheet_tag: preload: true`.
3. Other preloads, including fonts from `preload_tag`.
4. Script preloads.
5. Image preloads, from `image_tag: preload: true`.

Anything past the tenth entry is dropped. A `<head>` with 10 or more render-blocking resources leaves no room at all, so an LCP image preload, which sorts last, is the first thing to disappear. If a preload you added doesn't show up in the document's `Link` response header, then check how many render-blocking resources your `<head>` contains before you investigate anything else.

This is another reason to [reduce the number of render-blocking resources](https://shopify.dev/docs/storefronts/themes/best-practices/performance/reduce-stylesheet-count) in the `<head>`: each one both blocks rendering and competes for a preload slot.

`preload` differs from [`fetchpriority`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/set-fetchpriority-high-on-lcp-image): `preload` discovers a resource that the browser would otherwise find too late, while `fetchpriority="high"` increases the priority of a resource that the browser already knows about.

***

## How

### Valid use cases

* Fonts referenced late inside a separate CSS file.
* Critical files discovered late in parsing.
* After testing proves that it's beneficial.

### When not to preload

* Render-blocking scripts and stylesheets in the `<head>`, because Shopify already preloads them.
* Assets already in HTML, because the preload scanner finds them.
* More than two resources, because it degrades prioritization.
* Without before-and-after testing.
* To try to fix JavaScript rendering; fix the architecture instead.

### Prefer Shopify's Liquid filters

Use Liquid filters instead of plain HTML. They trigger [Early Hints (HTTP 103)](https://performance.shopify.com/blogs/blog/early-learnings-for-early-hints-at-shopify):

```liquid
{%- comment -%} Liquid filters trigger Early Hints {%- endcomment -%}
{{ 'font.woff2' | asset_url | preload_tag: as: 'font', type: 'font/woff2' }}
{{ 'critical.css' | asset_url | stylesheet_tag: preload: true }}
{{ product.featured_image | image_url: width: 800 | image_tag: preload: true }}
```

When Shopify renders a page with these Liquid filters:

1. Shopify converts the filters to `Link` headers automatically.
2. `Link` headers trigger Early Hints (HTTP 103 response).
3. The browser receives preload instructions before the main HTML.
4. Assets start downloading earlier than with HTML preload tags.

Benefits:

* Earlier discovery than HTML `<link rel="preload">`.
* No manual `Link` header management needed.
* Works with Early Hints.
* Assets are discovered while the server is still rendering the page.

**Note:**

Liquid filters work only for Shopify CDN assets. External assets require plain HTML `<link rel="preload">` tags in `<head>`.

***

## Examples

### Late-discovered fonts

```liquid
{%- comment -%} Font referenced in external CSS: late discovery {%- endcomment -%}
{{ 'font.woff2' | asset_url | preload_tag: as: 'font', type: 'font/woff2' }}


<link rel="stylesheet" href="{{ 'styles.css' | asset_url }}">
```

Without preload, the browser doesn't know about the font until after the CSS downloads and parses. With preload, the font downloads in parallel with CSS.

### Common misuse

Preloading assets already in HTML provides no benefit:

```html
<!-- Unnecessary: the preload scanner finds this -->
<link rel="preload" href="hero.jpg" as="image" />
<img src="hero.jpg" alt="Hero" />
```

***

## Testing

* **`Link` response header**: inspect it on the document request. It shows the preloads that Shopify sent, automatic ones included, and confirms whether your own hints survived the 10-entry cap.
* **Priorities Bookmarklet**: use this to audit the total number of preloads on your page. Keep your own to two or fewer.
* **[Chrome DevTools Network panel](https://developer.chrome.com/docs/devtools/network)**: verify that the preloaded resource downloads early and in parallel with other resources.
* **Before-and-after comparison**: always test your changes with multiple runs to confirm that `preload` is providing a benefit and not causing regressions.

***

## References

* [`preload_tag`](https://shopify.dev/docs/api/liquid/filters/preload_tag) filter
* [`stylesheet_tag`](https://shopify.dev/docs/api/liquid/filters/stylesheet_tag) filter
* [`image_tag`](https://shopify.dev/docs/api/liquid/filters/image_tag) filter
* [`asset_url`](https://shopify.dev/docs/api/liquid/filters/asset_url) filter
* [`image_url`](https://shopify.dev/docs/api/liquid/filters/image_url) filter
* [`product.featured_image`](https://shopify.dev/docs/api/liquid/objects/product#product-featured_image)
* [Introduction to preconnect and preload resource hints](https://performance.shopify.com/blogs/blog/introduction-to-resource-hints)
* [Early learnings for Early Hints at Shopify](https://performance.shopify.com/blogs/blog/early-learnings-for-early-hints-at-shopify)
* [AssetPreload Theme Check](https://shopify.dev/docs/storefronts/themes/tools/theme-check/checks/asset-preload)
* [Use Shopify image filters efficiently](https://shopify.dev/docs/storefronts/themes/best-practices/performance/use-shopify-image-filters-efficiently)
* [Mark the LCP image with `fetchpriority="high"`](https://shopify.dev/docs/storefronts/themes/best-practices/performance/set-fetchpriority-high-on-lcp-image)
* [Self-host web fonts on Shopify CDN](https://shopify.dev/docs/storefronts/themes/best-practices/performance/self-host-web-fonts)

***
