Steve Workman's Blog

A Primer on Preconnect

Posted on by Steve Workman About 2 min reading time

The best thing about technology, is that it's always changing. I learn new things every day, even in areas that I think I know a lot about, such as web performance.

See, when I was looking at performance optimisations for a project, I found a way to reduce connection times by getting the browser to speculatively perform DNS lookups for a list of third-party domains. This takes about 10-30ms off of the initial connection to a new domain. It may not sound like much, but it can make a big difference to how fast an image loads.

The last time I looked at this was before the internet went all-in on HTTPS, and so when I looked at the network timing of a new third-party HTTPS service, I was wondering if there was anything I could do to help the browser with the additional TLS negotiation and connection.

Waterfall showing DNS prefetch on a HTTPS resource

The affect shown here is achieved by adding a meta tag of

to theof the HTML. You can also do this by adding it as a header to the response of the HTML document.

That fetches the DNS, but not the TLS negotiation or the connection setup. There is a different hint that you can give to the browser that will do all of those things, called preconnect. It works much in the same way as dns-prefetch but sets up the rest of the connection as well. When working, it looks like this

The code here looks like this:

. That looks nice and easy, and you've just saved another fifty milliseconds on the first connection to that domain over HTTPS.

However, this is a web standard, so it's not all that simple. Firstly, the browser support for this hint is not brilliant with no support in IE or Safari. The best thing to do for those browsers is to keep the dns-prefetch hint as well as the preconnect hint.

Secondly, there is a limit to how many you can use effectively, and that limit is 6 connections. The reasons for this go back into the aeons of ancient internet history (read: the 90s) where browsers and internet routers were most efficient with 6 open connections at any one time. With modern routers and browsers, this isn't true, but these limits aren't likely to be changed any time soon due to this enormous internet legacy.

Finally, there is an extra attribute that you can add to this

tag called "crossorigin" which changes how preconnect makes its connections. As Ilya Grigorik explains in his post:

The font-face specification requires that fonts are loaded in "anonymous mode", which is why we must provide the crossorigin attribute on the preconnect hint: the browser maintains a separate pool of sockets for this mode.

What that means is that some resources, such as fonts, ES6 modules or XHR, need to be accessed in a "non-credentialed fetch", or crossorigin="anonymous". Otherwise, these resources won't load and you'll see a cancelled resource request in the network requests. the "anonymous" value is the default if just "crossorigin" is provided, so if you like shorthand, you don't need to add the ="anonymous" part to your code.

That's it. Preconnect is a really useful hint that can save milliseconds on those third-party requests. Give it a go.

For reference, my conversation started on Twitter with this tweet and ending with this tweet from Yoav Weiss