Resource hints provide a way to optimize the performance of your web page on the client side. As the name suggests, they provide the browser with hints about how the user will likely request resources such as fonts, images, and scripts while interacting with your site. By predicting the user’s expected behavior, the browser can prefetch, prerender, or preload resources in advance.
Technically speaking, resource hints are different values for the rel
attribute of the <link>
HTML element used for external resources. The user’s browser will use these values to prioritize resource links instead of treating them as if they’re of equal importance.
There are four types of resource hints, as specified by W3C:
dns-prefetch
preconnect
prefetch
prerender
Besides these four resource hints, there’s a fifth value of the rel
attribute that’s very similar to resource hints: preload
, which has its own W3C specs. It’s the upgraded version of the deprecated subresource prefetching feature that was available in Chrome and Opera for a while.
Even though preload
is not a resource hint (recommendation) but a mandatory directive that the browser must follow since it’s also a value for the rel
attribute, we’ll discuss it in this article too.
dns-prefetch
dns-prefetch
is the most lightweight resource hint that allows you to prerequest the smallest portion of a remote resource: its numeric IP address.
The dns-prefetch
resource hint tells the browser to conduct a DNS lookup for the resource while the user keeps browsing the page. During the DNS lookup, the user’s browser connects to the domain name server of the resource and translates the domain name (e.g., www.example.com
) into a numeric IP address. Since the browser performs this task in the background, the user won’t have to wait for the DNS resolution when they need the resource.
To use the DNS prefetch feature, add the rel="dns-prefetch"
attribute to the <link>
tag.
<link rel="dns-prefetch" href="https://example.com">
Although the <link>
tag usually goes into the <head>
section of the document, resource hints are body-ok, so you can also use them in the <body>
section if you want.
Because dns-prefetch
resolves only the domain name but doesn’t preconnect to the remote server or preload the resource, it requires little bandwidth. However, it can significantly improve DNS latency — the total request-response time between the DNS server and the user’s browser.
Latency can be high for a variety of reasons, such as when the DNS server is located far from the user’s machine or when many users attempt to access the server at the same time. So if you know that the domain where the resource is stored has high latency, it may be worth using DNS prefetch.
You’ll only need to use dns-prefetch
when the resource is hosted on a different domain, since you don’t need to resolve your own domain name.
dns-prefetch
is typically recommended when prefetching domain names for:
<script>
tagYou should also consider DNS prefetch when the same domain is referenced on your site multiple times since it’s very likely that your user will request at least one resource from that domain.
preconnect
preconnect
is a resource hint that prerequests a somewhat larger portion of the remote resource.
Besides translating the domain name into a numeric IP address like DNS prefetch, it also preconnects to the server where the resource is hosted. This early connection includes the DNS lookup and TCP handshake in the case of an HTTP connection, plus the TLS negotiation in the case of a secure HTTPS connection.
To use preconnect
, you need to use the rel
attribute together with the preconnect
value:
<link rel="preconnect" href="https://example.com"> <link rel="preconnect" href="https://cdn.example.com" crossorigin>
To handle CORS requests, you can also add the crossorigin
attribute to the <link>
tag. Without a specified value, the crossorigin
attribute will prevent the browser from exchanging user credentials via cookies with the other-origin server (it’s identical to crossorigin=anonymous
).
For the most part, you can use the preconnect
resource hint for the same things as dns-prefetch
. You should choose it if you’re fairly sure the user will really request the script, font, stylesheet, or other resource from the third-party server.
Since preconnect
exchanges more data, it also needs more bandwidth. So you have to be more careful with it to avoid slowing down the page and wasting your user’s bandwidth with redundant data.
The W3C specification also recommends preconnect for two specific use cases:
You can use preconnect
for dynamic URL requests when the final URL will be constructed later. This way, you can speed up the resource fetching process because the browser will have already been connected to the third-party server by the time the dynamic URL is created.
You can also use preconnect
to secure and anonymize redirects. If you preconnect to the server ahead of time, you can remove sensitive data such as the user ID or purchase details from referrer links.
This is important when you redirect users to third-party sites, such as advertisers’ websites. Even though you might not want to remove everything from the referrer link, advertisers still shouldn’t know user data that’s related only to your site but not to theirs.
prefetch
(link prefetch)The prefetch
resource hint goes a step further: in addition to resolving the domain name and preconnecting to the remote server (if it’s necessary), it also prefetches the resource and stores it in the browser’s cache.
However, there’s an important difference between prefetch and dns-prefetch
and preconnect
resource hints. While DNS prefetch and preconnect provide the browser with hints related to resources that will be loaded within the same page, prefetch focuses on resources that will be required by the next page/tab/navigation the user might visit after the current one.
To add the prefetch hint to a resource, you need to use the rel
attribute with the prefetch
value:
<link rel="prefetch" href="https://example.com/video.mp4" as="video" crossorigin> <link rel="prefetch" href="next-page.html" as="document">
You can use prefetch
together with two optional parameters: the previously mentioned crossorigin
, which lets you define how to handle CORS-requests, and as
, which allows you to specify the type of the prefetched resource.
The as
attribute can take different values, such as audio
, video
, image
, document
, script
, and font
, and can help you establish a Content Security Policy.
The prefetch
resource hint is mainly recommended for interactive applications when you have a high level of app-specific knowledge. You should only use this resource hint if you can predict with a high probability where the user will go next. Paginated content, image galleries, and step-driven flows are examples of when it can be reasonable to use prefetch.
The specs also mention that you can implement a reactive prefetch strategy by dynamically adding prefetch
to resources based on events generated by either the user or the application, such as clicks. When the event fires, you can start prefetching resources immediately when the navigation request/intent takes place so that they will be loaded sooner.
While dns-prefetch
and preconnect
are only recommended for third-party resources, prefetch
not only connects to a server but also downloads the resource, so you can use it for resources stored on your own domain too.
If you want to prefetch resources on the current page instead of the next one, you’ll need to use the preload directive instead of prefetch (more on this later).
prerender
The prerender
resource hint also focuses on the next page the user will likely visit, similar to prefetch
. However, prerender
takes an additional step and also executes the resource in addition to prefetching (requesting and downloading) it.
prerender
completely prepares the next page for view, including prefetching and executing all the subresources, such as images, videos, and scripts. With prerender
, you always fetch the next page as an HTML response, meaning a complete page. If you want to fetch a subsequent resource as another content type, such as an image or video, you should use the prefetch
hint instead.
To prerender the next page in the expected user flow, use the <link>
tag’s rel
attribute together with the prerender
value.
<link rel="prerender" href="next-page.html">
Just like prefetch
, prerender
is recommended for interactive applications in which user flows can be calculated with high probability. By prerendering the next page, you can implement an instant navigation experience within your application.
Because prerender
doesn’t only prefetch the subsequent resources but also executes them, you have to be even more careful with it. You can waste a significant amount of bandwidth by making a wrong prediction.
Also note that browser support for prerender
is not very good at the moment; Firefox and Safari don’t support it at all. From a support point of view, if you want to give hints about resources on the next page, it makes more sense to use prefetch
since it comes with better browser support.
preload
(not a resource hint)As mentioned before, preload
is not a resource hint but a directive that has its own W3C specification. The main difference between preload
and resource hints is that hints are only recommendations with low priority, so the user’s browser only implements them if it has idle time. preload
, on the other hand, has a high priority — it’s a mandatory fetch for resources needed on the current page.
When it comes to functionality, preload
is similar to the prefetch
resource hint. preload
also requests and downloads the resource without executing it, but on the current page instead of the subsequent one. Plus, it’s obligatory for the browser as opposed to the optional prefetch
.
To preload a resource on the same page, add the preload
value to the rel
attribute:
<link rel="preload" href="style.css" as="style"> <link rel="preload" href="https://example.com/font.woff2" as="font" crossorigin type="font/woff2">
Similar to prefetch
, you can use preload
together with the optional as
attribute to specify the type of the preloaded resource. Note that if you preload a CORS-enabled resource from a third-party domain, you’ll also need to use the crossorigin
attribute.
The most important thing to remember is that the preload
directive is not the same thing as the browser’s built-in preloader. While the browser’s preloader only fetches resources defined within the HTML document, the preload
directive also lets you preload resources specified within CSS and JavaScript.
In addition, if you preload resources with the preload
directive, the fetching process won’t be stopped by render-blocking resources, which happens to resources being fetched by the browser’s preloader. So, you can use preload
to set resource priority based on the specific needs of your application.
One common use case for preload
is the early fetching of critical resources. The specs detail how to prefetch important resources while the main document parser is being stopped by a render-blocking script. This is possible because preload
only downloads the resource but doesn’t execute it.
All in all, you need to treat preload
different than resource hints. Since it’s mandatory, you give the user’s browser not a recommendation but a command. You can use it to improve performance by optimizing the delivery order of resources on the current page. MDN published some useful tips (and code examples) about how to properly preload resources.
The trade-off for each resource hint is essentially the same: improving performance versus risking bandwidth waste. If you use resource hints well, you can significantly improve page load times. However, it’s not always easy to find out which resource hint to use and when.
If you make the wrong predictions about the user’s likely behavior, on the other hand, their browser will request unnecessary resources. This will make your site resource-heavy, increase latency, and cost the user extra bandwidth — which is especially bad if they access your site on a mobile device and/or metered data connection.
You also need to consider browser support. Currently, preconnect
has better support than dns-prefetch
and prefetch
has better support than prerender
. Since the mandatory preload
directive also has somewhat patchy support, you shouldn’t rely on it for functionality (meaning your scripts should also properly load on browsers that don’t support it); only use it for performance optimization on browsers that do support it.
Finally, if you use multiple resource hints and the structure/content of your site is frequently changing, maintenance will be hard if you just throw them into the HTML. You can easily prerequest a resource that you don’t use anymore on your site. In this case, it’s more reasonable to add resource hints dynamically using JavaScript so that you can keep all your resource hints in the same file and maintain them more easily.
Debugging code is always a tedious task. But the more you understand your errors, the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to see exactly what the user did that led to an error.
LogRocket records console logs, page load times, stack traces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowLearn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.
Efficient initializing is crucial to smooth-running websites. One way to optimize that process is through lazy initialization in Rust 1.80.