
Preloads are a powerful optimization technique that can make significant improvements to crucial performance metrics such as Core Web Vitals. I have written on prefetching a DNS lookup or even preconnecting to a domain. Preloading is a much more powerful extension of these concepts because it enables you to download entire resources in advance.
In this article, let’s look at:
- How preload resource hints work
- Guidance on when to use them (and when not)
- A checklist of best practices to follow when implementing preload hints on your own sites.
How preload resource hints works
A preload is a resource hint that tells the browser to request content before the browser has determined it needs to make the request. This can improve performance because when the browser does realize it needs to request a resource that has been preloaded, it is already there.
Let’s start with a simplified example, shown in this waterfall diagram:
The browser first downloads the HTML document, which references a stylesheet style.css. Inside the stylesheet, we specify a custom font that should be used, as shown below:
This is a perfect example of a late-discovered resource. This browser doesn’t know it needs to request roboto.woff until it finishes downloading and parsing style.css. We can confirm this by looking at the Initiator column in the waterfall, which tells us what file caused the browser to make the request. The HTML document has an initiator of Other because we typed it into the address bar. The initiator for style.css was the HTML document since the browser found the <link> tag in the HTML. The initiator roboto.woff was the CSS file since the browser found the @font-face declaration for a style in the CSS file that was used in the HTML.
We can optimize this by adding a preload resource hint in the <head> of the HTML file:
<link rel="preload" href="resources/roboto.woff" as="font" crossorigin="anonymous" />
This instructs the browser to proactively download roboto.woff, and creates this waterfall:
There are many things to note:
- The browser now downloads roboto.woff in parallel with style.css.
- The initiator for roboto.woff is the HTML file instead of the CSS.
- All major performance metrics are faster, and we have reduced the length of the critical rendering path.
Real-world examples
That was great for a demonstration – now let’s see the real-world benefits of using preload resource hints.
Addy Osmani shared how Tinder improved performance of their progressive web app (PWA). As a PWA, Tinder had large JavaScript bundles that would dynamically load in other JavaScript bundles. Since these additional bundles are dynamically loaded by the script executing, the browser cannot discover them until the JavaScript code runs. I’ve annotated a screen shot from Addy’s blog post below:
You can see how 3 additional JavaScript files are loaded by a main vendor bundle. By preloading these additional scripts, Tinder:
- Reduced load time by 1 second
- Decreased their first paint metric by roughly 50%
Ivan Akulov did some interesting performance analysis on the popular web app Notion. Notion requires the same basic API calls before it can function, and those API calls happen after the main bundles load. Preloading these API calls improved page render metrics by 10%.
At Splunk, we also have firsthand experience. In early 2020, we worked with a major media customer which had a substantial amount of JavaScript for a variety of third-party domains. By analyzing their site and implementing resource hints such, as preconnect and preload, we improved Time-to-Interactive by 4.9 seconds — that’s 37%.
When to use preload resource hints
In the case studies above, you will notice a pattern:
Like all resource hints, preloading allows you to use your knowledge of the app to optimize the delivery of resources better than the browser could ever do on its own.
Specifically, you are able to tell the browser to request a resource before it would have otherwise requested it. It is wasteful to tell the browser to download something it would have discovered on its own. For example, if you have style.css near the top of the HTML’s <head>, there is little reason to use a preload resource hint. The browser is already going to discover it.
Preload is ideal for late-discovered resources. A late-discovered resource is a resource that requires a chain of 1 or more other resources to be downloaded or executed before the browser gets to them. For example:
- Fonts that referenced inside a CSS file
- Critical resources that are dynamically loaded by JavaScript
- Images or content that only appear after an API call is made
Incorrectly using preload can hurt performance
Given the impressive gains described above, I know what you must be thinking:
If preload resource hints improve overall performance and user experience, why don’t I preload all the critical resources on a page?
Unfortunately, incorrectly using preload can actually hurt performance. Why? It’s simple: browsers use a lot of complex logic to decide what needs to be downloaded and when, so the page can render and be responsive for the visitor as quickly as possible.
A site using preload is essentially asking to override what the browser would normally do. This can be the source of different performance issues if used carelessly for three reasons:
- Preload resource hints are mandatory. While other types of resource hints, like preconnect or DNS-prefetch hints, the browser can choose to follow, preload hints are required to be executed. Modern browsers use incredibly sophisticated logic to download critical resources. Preloads — potentially more than any other type of resource hint — can interfere the most with the browser’s operation and must be used with care.
- Preloads use up resources. Browsers place limits on the number of simultaneous requests it will make to a single domain. Preloading a resource “uses up” a request slot and download bandwidth you think the browser needs, versus resources the browser would otherwise use for downloading resources that it knows it needs.
- Preloads happen at the most critical time. Preloads typically happen near the start of loading a page, which is the most critical time for the browser. It is focused on downloading resources on the critical rendering path, which are the resources required to start rendering the page. Too many or unnecessary preloads impacts the browser from doing the right thing, degrading performance.
Now let’s look at some common mistakes.
Excessive preload hints
One of the most common mistakes adopting preload hints is to use an excessive number of them. As a rule, websites should not preload more than 3-4 resources. Beyond that, you are trying to outsmart the browser, which is rarely a good idea. Here is why:
First, preloads work best on late-discovered resources that are also critical to the page. Having more than a handful of critical resources that also cannot be easily discovered by the browser is usually a symptom of a larger design problem.
For example, a site may be preloading six fonts. Are all six of those fonts needed for above-the-fold content? Would a single variable weight font file work instead? Another option would be to include the font-face: definitions directly in the HTML via a <style> tag. With that approach, those font files are no longer late-discovered resources. The browser can immediately see which of the six font files, if any, are needed and fetch it quickly without the need for a preload hint.
The second reason to avoid excessive preload hints is technical debt. The more preloads a page has, the more likely the chance that one of those preloads is not helping accelerate the initial loading and interactivity of the page. Each represents more technical debt to maintain and ensure that the preloaded resources remain critical to that page.
Preloading unused content
Another common mistake is to see a preload for content that isn’t even used by a page. I often see this when sites use a common header with their templates. A developer may be optimizing their home page or a critical landing page and include a <link rel=”preload”> for a key font or JavaScript file. They mistakenly put it in the common header, even though those resources aren’t used elsewhere on the site.
Luckily, modern browsers will display a warning in the console:
Looking for those warnings on all key pages can be tedious. Instead, a good proxy is to look at a site’s CSS and JavaScript coverage analysis. If a site is loading a large amount of CSS or JS that goes unused, it usually means the site owners are using large, coarse-grain general bundles for the entire site instead of smaller targeted bundles for their specific templates. It follows that any preloads may also be too coarse and are being preloaded across pages when they are not truly needed.
Preloading non-critical content
Another common mistake is to preload content that is not critical to the rendering and interactivity of the above-the-fold content. Usually if you have too many preloads, it is because you are preloading non-critical content.
- Are you preloading an image? Unless it is the hero image, and that hero image is truly a late-discovered resource, it’s probably not necessary.
- Are you preloading JavaScript? If so, is it critical to provide interactivity like CTA clicks? Why can’t the JavaScript be deferred or loaded asynchronously?
- Are you preloading a font? Is it used by this page, or is this preload happening in a common template header and the font is not used everywhere?
- Are you preloading a video? Why? Preloading a video is almost always a bad idea since it is, by definition, not critical content. Consider using the poster attribute on a <video> tag instead.
In general, if the <link rel=”preload” as=””> attribute is something besides style, script or font, it is usually non-critical and needs additional scrutiny.
Preloading non-existent content
The ultimate manifestation of preload neglect is when the preload results in a 404 — never good. 404s in the critical rendering path are bad. However, 404s for preloaded content are the worst. You have usurped the browser’s normal behavior, delaying resources that the browser knows it needs, all to download invalid content.
Preloading isn’t always the right hint for the job
Preload is different from other resource hints in that you specify a complete URL. Oftentimes, you can’t depend on that URL staying constant, or have no way of knowing what the full URL will be. For example:
- If the page is loading a JavaScript library from another department, the additional JavaScript libraries that it downloads can change. Using preload creates dependencies where you need to stay in sync with changes on which URLs from the additional JavaScript is loaded.
- If you use comments, you might not know what user avatar images get loaded, but you do know they all come from www.gravatar.com.
- If you are using an ad exchange, you may not know the path for the ad bidding, but you do know you will make a request to ads.pubmatic.com
These are great opportunities to use a preconnect or DNS prefetch instead. Remember: It is far better for performance to use a resource hint that does less work ahead of time, than to use a preload and be wrong.
Best practices for preload auditing
As we have shown, there are many benefits to using preload resource hints, but also many pitfalls that hurt performance if you use them incorrectly. This means it is important to audit how a page is using resource hints to ensure you are following all the best practices.
First, identify all the preload resource hints a page is currently using. You will want to look for <link rel=”preload”> tags in the base HTML page, as well as Link: HTTP headers which can also contain resource hints. Also remember that Link headers containing resource hints can appear on other responses beyond just the based HTML page!
Once you have the list of preloads, ask yourself the following questions:
- Is this resource a late-discovered resource or will the browser already discover it?
- Is the preloaded resource critical to the initial drawing or interactivity of above-the-fold content? If not, remove it.
- Are you preloading more than 3-4 resources? If so, have you tested to see if these preloads improve performance metrics?
- Is the preloaded resource something other than a font, CSS or JavaScript file? If so, it’s probably not critical to the page, and most likely should be removed.
- Is this preloaded resource used by the page? If not, remove it.
- Is this preload resource returning a 4xx or 5xx error? If so, remove it
- Is the resource hint included in a common header used by other pages? Is this resource used for all of those pages? If not, only include the preload hint on pages that need it.
If you are looking for a more automated solution or want to do this validation at scale, you have options. Splunk Synthetic Monitoring automatically audits pages for different issues that can occur when using resource hints.
As with all performance optimizations, you should always measure before and after to ensure the change actually improves performance. Yes, in theory, preload hints should speed things up. But modern web pages are complex with hundreds of resources, and modern browsers are even more complex to handle those resources quickly to deliver the best experience. Trust, but verify.
What is Splunk?
The original version of this blog was published by Billy Hoffman. This posting does not necessarily represent Splunk's position, strategies or opinion.