What’s even cooler is that browsers have a simple built-in way to do all these things. There’re five <link rel>
tags that instruct the browser to preload something:
<link rel="prefetch" href="/style.css" as="style" />
<link rel="preload" href="/style.css" as="style" />
<link rel="preconnect" href="https://example.com" />
<link rel="dns-prefetch" href="https://example.com" />
<link rel="prerender" href="https://example.com/about.html" />
Here’s what they each of them does and when to use them.
Jump to: preload · prefetch · preconnect · dns-prefetch · prerender
preload
<link rel="preload">
tells the browser to download and cache a resource (like a script or a stylesheet) as soon as possible. It’s helpful when you need that resource a few seconds after loading the page, and you want
to speed it up.
The browser doesn’t do anything with the resource after downloading it. Scripts aren’t executed, stylesheets aren’t applied. It’s just cached – so that when something else needs it, it’s available immediately.
Syntax
<link rel="preload" href="/style.css" as="style" />
href
points to the resource you want to download.
as
can be anything you can download in a browser:
style
for stylesheets,script
for scripts,font
for fonts,fetch
for resources downloaded withfetch()
orXMLHttpRequest
,- other values – see the full list on MDN
as
attribute – it helps the browser to prioritize and schedule the download properly.
When to use
Use it when you’ll need a resource soon.<link rel="preload">
will help when you know you’ll need a resource soon after loading the page, and you want to start loading it earlier. For example:
- You use custom fonts. The
@font-face
rule that applies those fonts is in an external CSS file:<!-- index.html --> <link rel="stylesheet" href="index.css" />
/* index.css */ @font-face { src: url('comic-sans.woff2') format('woff2'); }
By default,
comic-sans.woff2
will start downloading only whenindex.css
is fetched and applied. Instead of waiting for it that long, use<link rel="preload">
to initiate the download sooner:<link rel="preload" href="comic-sans.woff2" as="font" />
- You split your styles per the Critical CSS approach. With this approach, you’ll split your CSS into two parts – critical (required for immediate rendering) and non-critical:
<style> /* Inlined critical styles */ </style> <script> /* Custom JS that starts downloading non-critical styles */ loadCSS('/app/non-critical.css'); </script>
With this approach, non-critical styles will start downloading only when JavaScript starts executing – which can be a few seconds after the first render. Instead of waiting for JS to execute, use
<link rel="preload">
to initiate the download sooner:<style> /* Inlined critical styles */ </style> <link rel="preload" href="/app/non-critical.css" as="style" /> <script> /* Custom JS that starts downloading non-critical styles */ loadCSS('/app/non-critical.css'); </script>
Don’t confuse with prefetch
. Don’t use <link rel="preload">
if you don’t need a resource immediately after the page loads. If you only need it later – e.g., for a next page – use <link rel="prefetch">
.
More details
It’s mandatory. Unlike all other preload-related<link>
tags, this tag is mandatory for the browser (if it supports the tag). A browser has to download the resource specified in <link rel="preload">
.
With other tags described here, a browser is free to skip preloading the resource if it decides to – e.g. if the network is slow.
Priorities. For different kinds of resources (styles, scripts, fonts, etc.), browsers typically assign different priorities. This allows for downloading the most important resources first. For a resource fetched with <link rel="preload">
,
browsers use the as
attribute to determine its priority. For Chrome, see the full table of Chrome priorities for more details
2) How I find what to preload:
— Go to DevTools and run a performance recording of how the page loads
— Scroll through the Network section and find stuff that blocks page rendering but gets downloaded too late (= too much down in Network section). That’s usually CSS or JS
1/2 pic.twitter.com/5Uem9U34jc— Ivan Akulov (@iamakulov) January 2, 2019
prefetch
<link rel="prefetch">
asks the browser to download and cache a resource (like, a script or a stylesheet) in the background. The download happens with a low priority, so it doesn’t interfere with more important resources.
It’s helpful when you know you’ll need that resource on a subsequent page, and you want to cache it ahead of time.
The browser doesn’t do anything with the resource after downloading it. Scripts aren’t executed, stylesheets aren’t applied. It’s just cached – so that when something else needs it, it’s available immediately.
Syntax
<link rel="prefetch" href="/style.css" as="style" />
href
points to the resource you want to download.
as
can be anything you can download in a browser:
style
for stylesheets,script
for scripts,font
for fonts,fetch
for resources downloaded withfetch()
orXMLHttpRequest
,- other values – see the full list on MDN
as
attribute – it helps the browser to prioritize and schedule the download properly.
When to use
Use it for resources from other pages.<link rel="prefetch">
will help if you need a resource on a different page, and you want to preload it and speed up rendering of that page. For example:
- You have an e-commerce site, and 40% of your users go from the home page to a product page. Use
<link rel="prefetch">
to download CSS and JS files responsible for rendering product pages - You have a single-page app, and you code-split it so that different pages load different bundles. When a user visits some page, ask your router what other pages it links to, and use
<link rel="prefetch">
to preload bundles for those pages
Don’t use for urgent resources. Don’t use <link rel="prefetch">
when you’ll need a resource in a few seconds. In this case, use <link rel="preload">
instead.
More details
Not mandatory. The browser is not required to follow the<link rel="prefetch">
instruction. This means it can decide not to fetch the resource – e.g. if the connection is slow.
Priorities in Chrome. In Chrome, <link rel="prefetch">
downloads are usually prioritized with the lowest priority (full table of priorities).
This means they are usually scheduled after everything else got loaded.
preconnect
<link rel="preconnect">
asks the browser to perform a connection to a domain in advance. It’s helpful when you know you’ll download something from that domain soon, but you don’t know what exactly, and you want to
speed up the initial connection.
A browser has to set up a connection when it retrieves something from a new third-party domain. (A third-party domain is a domain that’s different from the one your app is hosted on.) This may happen when a site uses a font from Google Fonts, loads React from a CDN, or requests a JSON response from an API server.
Setting up a new connection typically takes several hundred milliseconds. It’s only needed once per domain, but it still takes time. If you set up a connection in advance, you’ll save that time and load resources from that domain faster.
Syntax
<link rel="preconnect" href="https://api.my-app.com" />
href
points to the domain name you want to resolve. Feel free to specify it with the scheme (https://domain.com
) or without it (//domain.com
), it would work the same.
When to use
Use it for domains you’ll need shortly.<link rel="preconnect" />
will help you when you have an important style, script, or image on a third-party domain, but you don’t know the resource URL yet.
For example:
- Your app is hosted at
my-app.com
, and it makes AJAX requests toapi.my-app.com
. You don’t know what specific requests you’ll be making to that domain – because you make them dynamically from JS.Use
<link rel="preconnect">
to connect toapi.my-app.com
in advance and make the first data request faster - Your app is hosted at
my-app.com
, and it uses Google Fonts. Google Fonts load fonts in two stages: first, a CSS file is downloaded fromfonts.googleapis.com
; then, that CSS file requests fonts fromfonts.gstatic.com
.You can’t know what specific font files from
fonts.gstatic.com
you’ll need until you download the CSS file fromfonts.googleapis.com
. Use<link rel="preconnect">
to set up a connection in advance
<link rel="preconnect" />
for that domain. It will instruct the
browser to setup connection for that domain sooner.
Don’t overuse it. Setting up and keeping a connection open is costly – both for a client and a server. Use this tag for 4-6 domains at most.
More details
Not mandatory. The browser is not required to follow a<link rel="preconnect">
instruction. This means it can decide not to set up a new connection – e.g., if there’re already a lot of
connections set up, or in some other case.
What the connection process includes. To connect to each site, a browser has to perform the following steps:
- DNS resolution. Find a server’s IP address (
216.58.215.78
) for a specified domain name (google.com
) - TCP handshake. Perform a roundtrip (a message goes client → server → client) to initiate a TCP connection to a server
- TLS handshake (only for HTTPS sites). Perform two roundtrips (a message goes client → server → client → server → client) to initiate a secure TLS session
dns-prefetch
<link rel="dns-prefetch">
asks the browser to perform a DNS resolution of a domain in advance. It’s helpful when you know you’ll connect to that domain soon, and you want to speed up the initial connection.
A browser has to perform a DNS resolution when it connects to a new third-party domain. (A third-party domain is a domain that’s different from the one your app is hosted on.) This may happen when your site uses a font from Google Fonts, loads React from a CDN, or requests a JSON response from your API server.
For each new domain, resolving the DNS record usually takes around 20-120 ms. It only affects the first resource downloaded from that domain, but it still matters. If you perform a DNS resolution in advance, you’ll save that time and load that resource faster.
Syntax
<link rel="dns-prefetch" href="https://api.my-app.com" />
href
points to the domain name you want to resolve. Feel free to specify it with the scheme (https://domain.com
) or without it (//domain.com
), it would work the same.
When to use
Use it for domains you’ll need shortly. <link rel="dns-prefetch" />
will help you when you have some important resources on third-party domains the browser doesn’t know about in advance. For example:
-
Your app is hosted at
my-app.com
, and it makes AJAX requests toapi.my-app.com
. The browser doesn’t know that you’ll be making requests to that domain – because you make them from JS.Use
<link rel="dns-prefetch">
to resolveapi.my-app.com
and make the first data request faster -
Your app is hosted at
my-app.com
, and it uses Google Fonts. Google Fonts load fonts in two stages: first, a CSS file is downloaded fromfonts.googleapis.com
; then, that CSS file requests fonts fromfonts.gstatic.com
.The browser doesn’t know that you’ll load fonts from
fonts.gstatic.com
, so use<link rel="dns-prefetch">
to resolve it in advance
Use it to slightly speed up some third-party script or style. If you have a third-party resource in the page that you really need to load sooner, add <link rel="dns-prefetch" />
for that domain. It will instruct
the browser to schedule DNS resolution for that domain sooner.
Note on <link rel="dns-prefetch" />
and <link rel="preconnect" />
. Using both of these tags for the same domain is not really useful – <link rel="preconnect" />
already includes
everything <link rel="dns-prefetch" />
does, and more. However, it can still make sense in two cases:
-
You want to support older browsers.
<link rel="dns-prefetch" />
is supported starting from IE10 and Safari 5.<link rel="preconnect" />
has been supported in Chrome and Firefox for a while, but was added to Safari only in 11.1, and still isn’t supported in IE/Edge. If you need to support those browsers, use<link rel="dns-prefetch" />
as a fallback for<link rel="preconnect" />
. -
You want to speed up more than 4-6 domains. It’s not recommended to use
<link rel="preconnect" />
with more than 4-6 domains, as opening and keeping a connection is an expensive operation.<link rel="dns-prefetch" />
is more lightweight, so use it for other third-party domains if you want to speed them up too.
More details
Not mandatory. The browser is not required to follow a <link rel="dns-prefetch">
instruction. This means it can decide not to perform the DNS resolve – e.g., if there's already a lot of them, or in some
other case.
What is DNS. Each server on the internet is addressed by a unique IP address which looks like 216.58.215.78
. However, when you visit a site, you don’t type a server’s IP address – you use a site domain (like google.com
).
This works thanks to DNS (Domain Name System) servers – servers that map a domain (google.com
) to a server’s IP address (216.58.215.78
).
To resolve a domain name, the browser has to perform a request to a DNS server. This is what takes those 20-120 ms when you connect to a new third-party domain.
DNS is cached, though not reliably. Some operating systems and browsers cache your DNS requests. This would save time if you need to retrieve something from a third-party domain again – but don’t rely on it. Linux typically doesn’t have DNS caching at all. Chrome has a DNS cache, but it only lives for a minute. Windows caches DNS responses for 5 days.
prerender
<link rel="prerender">
asks the browser to load a URL and render it in an invisible tab. When a user clicks on a link to that URL, the page should be rendered immediately. It’s helpful when you’re really sure a user will visit a
specific page next, and you want to render it faster.
Despite (or because of?) its power, in 2019, <link rel="prerender">
has bad support in major browsers. See More details for more.
Syntax
<link rel="prerender" href="https://my-app.com/pricing" />
href
points to the URL you want to render in the background.
When to use
When you’re really sure a user will go to some page next. If you have a conversion funnel where 70% of visitors go from page A to page B, <link rel="prerender" />
in page A might help to render page B super-quickly.
Don’t overuse it. Pre-rendering a page is extremely costly – both in terms of traffic and memory. Don’t use <link rel="prerender" />
for more than one page.
More details
Not mandatory. The browser is not required to follow a <link rel="prerender">
instruction. This means it can decide not to perform the prerender – e.g., if the memory is low, or the connection is slow.
Chrome doesn’t do a full render. Instead of a full render, Chrome makes a NoState Prefetch to save memory. This means Chrome downloads the page and all subsequent resources, but doesn’t render it or execute JavaScript.
Firefox and Safari don’t support this tag at all. This doesn’t break the specification, as browsers are not required to act on the tag; but this is still quite sad. Firefox has an implementation bug which has been open for 7 years; and there are reports that state Safari doesn’t support it too.
Summing up
Use:
<link rel="preload">
– when you’ll need a resource in a few seconds<link rel="prefetch">
– when you’ll need a resource on a next page<link rel="preconnect">
– when you know you’ll need a resource soon, but you don’t know its full url yet<link rel="dns-prefetch">
– also when you know you’ll need a resource soon, but you don’t know its full url yet (for older browsers)<link rel="prerender">
– when you’re certain users will navigate to a specific page, and you want to speed it up
This article was brought to you by PerfPerfPerf. We help companies to earn more by making web apps faster.
Have a web performance issue or just want to learn what to improve? We’d be glad to help