Resource Hints and Preloading: Anticipating User Needs
Browsers discover resources — CSS, fonts, images, scripts — as they parse HTML. This sequential discovery creates waterfalls: a font file referenced in CSS cannot begin downloading until the CSS itself has downloaded and parsed. Resource hints short-circuit this discovery process by telling the browser about resources it will need before it encounters them naturally. Used correctly, hints eliminate round trips and can reduce LCP by hundreds of milliseconds. Used incorrectly, they waste bandwidth and actually slow the page down.
The Resource Hint Taxonomy
Four resource hint types serve different stages of the resource loading pipeline. Understanding what each one does — and what it costs — is essential for effective use.
dns-prefetch
Performs DNS resolution for a domain before the browser encounters a resource from that domain. DNS resolution typically takes 20-120ms, and the cost of a prefetch is negligible — it sends a single DNS query. Use it for third-party domains that the page might need (analytics, ad networks, font providers).
preconnect
Completes the full connection setup — DNS resolution, TCP handshake, and TLS negotiation — before the browser needs resources from that domain. On HTTPS connections, this saves 100-300ms (one DNS lookup + one TCP round trip + one TLS round trip). Use it for domains you know the page will use, such as API endpoints and CDN origins.
Limit preconnects to 2-4 domains. Each preconnect holds a TCP connection open. Excessive preconnects consume connection slots, potentially delaying higher-priority requests. If a preconnected domain is not used within 10 seconds, the browser closes the connection — wasting the setup cost entirely.
preload
Fetches a specific resource at high priority before the browser would naturally discover it. This is the most powerful hint and the most dangerous if misused. A preloaded resource that is not used within 3 seconds triggers a console warning and wastes bandwidth that could have been used for actual page resources.
The canonical use case is fonts. Fonts referenced in CSS cannot begin downloading until the CSS downloads, parses, and the browser determines a font-face rule matches an element on the page. A preload hint in the HTML <head> starts the font download immediately, eliminating this dependency chain.
prefetch
Fetches a resource at low priority for use on a future navigation. Unlike preload (which is for the current page), prefetch is speculative — it downloads resources that might be needed if the user navigates to another page. The browser fetches these only when idle, so they do not compete with current-page resources.
Preloading for LCP Optimization
The LCP element is often an image or a background image set in CSS. Both suffer from late discovery — the browser cannot start downloading the image until it has parsed the HTML far enough to encounter the element, loaded the CSS, and determined the image URL. Preloading the LCP image eliminates this cascade.
Identifying the LCP Element
Before adding a preload, identify what the LCP element actually is. Use Chrome DevTools Performance panel or RUM data to determine the LCP element across different page templates and viewport sizes. The LCP element varies: on a product page it may be the hero image; on a blog post it may be a heading rendered in a web font.
Responsive Image Preloading
For responsive images using srcset, the preload tag supports imagesrcset and imagesizes attributes, allowing the browser to select the correct image variant based on viewport width — just as it would from a <picture> or <img srcset> element, but with earlier discovery.
Font Loading Strategy
Web fonts are the most common resource hint target because their loading waterfall is uniquely deep: HTML → CSS download → CSS parse → CSSOM construction → layout → font download → text render. Preloading cuts this to: HTML → font download (parallel with CSS).
| Strategy | FOUT/FOIT | LCP Impact | Bandwidth |
|---|---|---|---|
| No preload, font-display: swap | FOUT (text visible immediately in fallback) | Neutral — fallback font renders | Minimal |
| Preload + font-display: swap | Reduced FOUT — font arrives faster | Improved if font is LCP | Font downloaded even if unused |
| Preload + font-display: optional | No FOUT — font used only if cached | Best for repeat visits | Font downloaded but may not be used |
| System fonts only | None | Best LCP possible | Zero font bandwidth |
Font Subsetting
Preloading a 200KB font that contains 4000 glyphs when the page uses 80 characters is wasteful. Subset fonts to include only the character ranges the page actually uses. A Latin-only subset of a typical variable font reduces file size from 200KB to 30-50KB — making the preload faster and reducing bandwidth consumption.
Common Mistakes and Anti-Patterns
- Preloading everything: When everything is high priority, nothing is. More than 5-6 preloads per page causes resource contention and can actually slow down critical resources. Preload only what genuinely cannot wait for natural discovery.
- Preloading without using: A preloaded resource not used within 3 seconds wastes bandwidth and triggers a console warning. This commonly happens when preloading images for a carousel slide that the user may never view, or preloading a font variant that only appears in specific content.
- Wrong
asattribute: Theasattribute tells the browser the resource type so it can set the correct priority and apply content security policies. A preload withas="script"for a font file receives the wrong priority and fails CORS checks. - Missing
crossorigin: Font preloads requirecrossorigin="anonymous"even for same-origin fonts. Without it, the browser fetches the font twice — once from the preload (without CORS) and once from the CSS@font-facerule (with CORS). - Preconnecting to your own domain: The browser already has a connection to the page's origin. Preconnecting to it is a no-op that adds HTML weight with zero benefit.
Measuring Hint Effectiveness
Adding hints without measurement is guessing. Track these metrics before and after each hint:
- Resource timing waterfall: Compare the start time of the hinted resource in Chrome DevTools Network panel. An effective preload shifts the resource's start time earlier, closer to navigation start.
- LCP timing: If the hint targets the LCP element, measure LCP change in field data. A preload that reduces lab LCP but shows no field improvement may indicate the LCP element varies across users.
- Wasted bytes: Chrome DevTools Coverage panel shows resources that were downloaded but not used. Cross-reference preloaded resources against actual usage to identify waste.
- Connection count: Monitor active connections in the Network panel. Excessive preconnects show as idle connections that eventually close without being used.
Dynamic Hint Strategies
Static hints in HTML work for resources that every page visitor needs. But some resources are conditional — an image that only appears above the fold on desktop viewports, or a script that loads based on user interaction. Dynamic hints serve these cases:
- Viewport-based hints: Serve different preload hints based on device type using server-side
Client-Hintsheaders (Viewport-Width,DPR). This prevents preloading a 2x retina image for users on 1x displays. - Interaction-based prefetch: Prefetch resources on hover or focus rather than on page load. When a user hovers over a navigation link, prefetch the destination page's critical resources. This provides 100-300ms head start with zero waste — the fetch only triggers on genuine user intent.
Key Takeaways
Resource hints eliminate loading waterfalls by telling the browser about resources before natural discovery. Use dns-prefetch broadly for third-party domains, preconnect sparingly for domains you will definitely use (limit to 2-4), preload precisely for the LCP element and critical fonts (limit to 5-6 per page), and prefetch for likely next-page resources during idle time. Always measure effectiveness with field data — an unused preload is worse than no preload. Every hint should have a clear target metric it improves and be validated against that metric after deployment.