Performance
preconnect, dns-prefetch and preload: when they pay
Three hints, three costs: preconnect opens a connection, dns-prefetch resolves the name, preload fetches now. On our site the handshake costs 59 ms.
Key points
- preconnect anticipates DNS, TCP and TLS; dns-prefetch anticipates only name resolution.
- preload fetches a resource now and can steal bandwidth from the LCP image.
- On our site the measured handshake costs 59 ms, 17% of a 350 ms first byte.
- A font preload without crossorigin downloads the file twice.
preconnect opens the connection to another origin early, dns-prefetch resolves only the name, preload fetches a resource the first paint needs straight away. Every hint removes work from the critical path and adds another piece.
What each hint does
| Hint | What it anticipates | Cost when wrong | When to use it |
|---|---|---|---|
| dns-prefetch | DNS resolution | a few ms of CPU, no connection | likely but unconfirmed origins |
| preconnect | DNS, TCP and TLS | a socket open even when unused | two or three critical origins |
| preload | Download of the resource | bandwidth taken from more important files | fonts and the LCP image |
| modulepreload | Download and parse of the module | a duplicate chunk when the graph changes | module entries |
| prefetch | Download for the next navigation | bandwidth wasted when the user never goes | likely links |
The rule of thumb: preconnect for origins you use within the first second, preload for the resources that draw the first screen, prefetch for the next navigation.
Counting the hints you ship
curl -s https://example.com/ | grep -o 'rel="[a-z-]*"' | sort | uniq -c | sort -rn
The command needs curl and grep and reads the HTML as the server sends it, before JavaScript adds anything. When the preload count passes three or four entries, you are fetching ahead resources nobody sees.
The five-font case
On our site the five preloads are 172,868 bytes before the first paint: two Averia cuts for headings, one Inter for body text and two General Sans for the interface. The cost holds because the fonts sit on the same origin and land in cache; on an external CDN the same list would need one preconnect, not five preloads.
The limitation to name
Hints are heuristics, not guarantees: the browser may ignore a preload when bandwidth is saturated or when the resource is not referenced at the right moment yet. On slow connections one extra preload makes LCP worse instead of better, so measure before and after.
Where to continue
The EneUI catalogue indexes 111,985 components, 12,808 icons and the record zoom parallax: a component with remote images needs a preconnect to the CDN, one with local images does not. For text that moves while fonts load read font-display and CLS, for images images without dimensions, and for the comparison of architectures frontend frameworks compared.
Frequently asked questions
Are preconnect and dns-prefetch alternatives?
No, they stack. preconnect also resolves DNS, so on the same origin dns-prefetch becomes redundant.
How many preconnects can I add?
Two or three. Each preconnect opens a socket, and ten open sockets compete with the resources you are already downloading.
Does a font preload work without crossorigin?
No. A font is a CORS request: without crossorigin the browser downloads the file twice, once for the preload and once for the CSS.
When does a preload make things worse?
When the resource is not needed for the first paint or when bandwidth is already saturated. It takes the queue and delays the LCP image.
Is prefetch useful in a SPA?
Barely, because the SPA loads its chunks with dynamic import(). modulepreload on the entry or a prefetch of the next route chunk matters more.