RevealTheme logo
Back to Blog

DNS Prefetch, Preconnect, and Preload Explained

DNS Prefetch, Preconnect, and Preload Explained
The RevealTheme Team

By

·

Open the source of almost any WordPress site and you'll find a small cluster of <link rel="..."> tags near the top of the <head>. These are resource hints — instructions you give the browser about work it can start before it would normally discover the need. Used correctly, dns-prefetch, preconnect, and preload can shave hundreds of milliseconds off your Largest Contentful Paint. Used carelessly, they waste bandwidth, fight your browser's own scheduler, and occasionally make a page slower. The three are constantly conflated, so let's pull them apart precisely.

What each hint actually does

The key to keeping these straight is to think about the connection setup sequence a browser performs before it can download anything from a new origin:

  1. DNS resolution — turn fonts.gstatic.com into an IP address.
  2. TCP handshake — open the socket (the SYN/SYN-ACK/ACK round trip).
  3. TLS negotiation — exchange certificates and agree on encryption.

Only after all three is the browser ready to ask for a file. Each hint front-loads a different slice of this pipeline.

dns-prefetch — resolve the name early

<link rel="dns-prefetch" href="//cdn.example.com"> tells the browser to do only step 1: look up the IP for an origin you'll probably use later. It's cheap, low-risk, and broadly supported (including older Safari, where preconnect behaves less reliably). DNS lookups typically cost 20–120ms depending on the resolver and whether the record is cached, so this is a small but real saving for third-party hosts you reference but don't load immediately.

preconnect — open the whole connection early

<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> does steps 1, 2, and 3. The browser finishes the DNS lookup, completes the TCP handshake, and runs the full TLS negotiation, then holds the warm connection open ready for a request. On a high-latency mobile connection that handshake-plus-TLS can easily be 200–500ms, so preconnect is far more powerful than dns-prefetch — and far more expensive. An open connection consumes resources on both ends, and browsers will quietly close a preconnected socket they decide is idle (Chrome after roughly 10 seconds), wasting the effort. Reserve preconnect for the two or three origins that deliver render-critical assets, and let dns-prefetch handle the rest.

preload — fetch a specific file early

preload is a different category entirely. The first two hints warm up connections; preload fetches an actual file: <link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>. It tells the browser "I know you'll need this exact resource, so download it at high priority now rather than waiting to discover it deep in a CSS file." Preload is the right tool for resources the browser finds late — web fonts referenced inside stylesheets, an LCP hero image set via CSS background-image, or a critical script. The mandatory as attribute sets the correct priority and lets the browser apply the right Accept headers; omit it and the resource is fetched twice.

How these show up in WordPress by default

WordPress has shipped automatic resource hints since version 4.6 via the wp_resource_hints filter. Out of the box it emits a dns-prefetch for s.w.org (used by the emoji and Open Sans fallback) and adds preconnect hints for fonts when a block theme registers them. Since WordPress 6.3, the core "Speculative Loading" direction and the fonts API also began emitting preconnect for fonts.googleapis.com and fonts.gstatic.com when you use the theme.json fonts feature. That's helpful, but most real-world hints come from your plugins and theme, and they're rarely curated.

You can see exactly what your site emits by viewing source and searching for rel="dns-prefetch", rel="preconnect", and rel="preload". Expect to find a tangle: an analytics script, a tag manager, a Google Fonts link, an embedded video host, a chat widget, and a payment processor each contributing their own.

Adding your own hints the right way

The clean, theme-update-safe approach is the core filter. Drop this in a child theme's functions.php or a site-specific plugin:

  • Hook wp_resource_hints, check the $relation_type argument, and append your URL to the matching array.
  • Use it for dns-prefetch and preconnect, which the filter handles natively.
  • For preload, which depends on a specific URL that may be cache-busted, hook wp_head at an early priority and print the tag directly, or use a performance plugin that resolves the hashed asset path for you.

If you'd rather not touch code, several caching and optimization plugins expose these settings. WP Rocket has a dedicated "Preload" tab plus a "Prefetch DNS Requests" box where you paste origins one per line, and it can preconnect to your CDN automatically. Perfmatters offers granular preload/preconnect/dns-prefetch fields and an "instant.page" style prefetch-on-hover. FlyingPress auto-preloads the LCP image and critical fonts. Whatever you use, the rule is the same: add hints deliberately, then re-measure.

The mistakes that actually hurt

  • Preconnecting to everything. Each preconnect opens a real connection. Beyond three or four, you're tying up the browser's connection budget on origins that may not be needed for first paint, which can delay the resources that are. Chrome will even warn in the console when you preconnect to an origin and then never use it.
  • Forgetting crossorigin on fonts. Fonts are always fetched anonymously (CORS mode). A preconnect or preload for a font without the crossorigin attribute opens or fetches on the wrong connection, so the browser ignores it and does the work twice. This is the single most common preload bug in WordPress.
  • Preloading below-the-fold assets. Preload means "high priority, fetch now." Preload a hero image, not the footer logo. Preloading non-critical resources steals bandwidth from your LCP element and can push your Largest Contentful Paint above the 2.5s "good" threshold.
  • Leaving stale hints from removed plugins. Deactivated a chat widget but its preconnect lingers because another plugin cached the head? Audit periodically.
  • Treating dns-prefetch and preconnect as interchangeable. They are not. If a render-critical font host gets only a dns-prefetch, you've saved 50ms when you could have saved 300.

A sensible default for a typical WordPress site

For most sites, this is the configuration that earns its keep:

  • preconnect (with crossorigin where needed) to your font host and your CDN — the origins that deliver above-the-fold assets.
  • dns-prefetch for everything else third-party: analytics, tag manager, ad networks, embedded media, chat — present but not blocking first paint.
  • preload for your one self-hosted web font subset (WOFF2) and your LCP image if it's set via CSS rather than a discoverable <img> tag.

The best long-term move, though, is to reduce the number of origins entirely. Self-host your Google Fonts (WordPress 6.4+ and plugins like OMGF make this trivial, and it's now a GDPR consideration in the EU too), and the preconnect to fonts.gstatic.com disappears along with two extra connection setups. Fewer origins beats faster connections to many origins.

Verify, don't assume

Resource hints are easy to get subtly wrong, so always confirm the effect. Run the page through PageSpeed Insights or WebPageTest and look at the connection view: you want to see DNS, TCP, and TLS already completed before your critical assets request. Check the browser console for Chrome's unused-preload and unused-preconnect warnings. And compare LCP before and after — if a hint didn't move a metric you care about, remove it. A resource hint that doesn't measurably help is just extra bytes in your <head>.