{"componentChunkName":"component---src-templates-blog-post-js","path":"/blog/2023-06-12-resource-hints/","result":{"data":{"markdownRemark":{"id":"6d7d08e0-4db3-56b1-9fc6-a0be1f942fe4","html":"<p>Every millisecond on the critical path counts. By the time your HTML parser reaches a <code>&#x3C;link rel=\"stylesheet\"></code> or a <code>&#x3C;script src=\"...\"></code>, the browser still has to resolve DNS, open a connection, negotiate TLS, and only then download the file. <strong>Resource hints</strong> let you start some of that work earlier—often while the document is still streaming—so that when the real request arrives, the network is already warm.</p>\n<p>They are not a replacement for good bundling, caching, or CDN placement. They are a small, declarative layer you add in <code>&#x3C;head></code> (or via <code>Link</code> response headers) to nudge the browser toward work you already know you will need.</p>\n<h2>The hint family</h2>\n<p>All resource hints share the same mechanism: a <code>&#x3C;link></code> element (or an HTTP <code>Link</code> header) with a specific <code>rel</code> value and, for fetch-related hints, an <code>href</code> pointing at a URL.</p>\n<table>\n<thead>\n<tr>\n<th>Hint</th>\n<th>What it does</th>\n<th>Typical use</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>dns-prefetch</strong></td>\n<td>Resolves the hostname to an IP address</td>\n<td>Third-party origins you will call later (analytics, fonts, API)</td>\n</tr>\n<tr>\n<td><strong>preconnect</strong></td>\n<td>DNS + TCP + TLS (full connection setup)</td>\n<td>Origins where you will fetch several resources soon</td>\n</tr>\n<tr>\n<td><strong>prefetch</strong></td>\n<td>Low-priority fetch of a resource for a <em>future</em> navigation</td>\n<td>Next page in a flow, likely user click</td>\n</tr>\n<tr>\n<td><strong>preload</strong></td>\n<td>High-priority fetch of a resource for the <em>current</em> navigation</td>\n<td>Hero image, critical font, above-the-fold CSS chunk</td>\n</tr>\n<tr>\n<td><strong>modulepreload</strong></td>\n<td>Preload for ES modules (also pre-parses the module graph)</td>\n<td>Entry or shared chunks in a module-based app</td>\n</tr>\n</tbody>\n</table>\n<p>Think of them on a spectrum from cheapest to most committed:</p>\n<pre><code>dns-prefetch  →  preconnect  →  prefetch / preload / modulepreload\n   (DNS only)     (connection)        (actual download)\n</code></pre>\n<h2>dns-prefetch</h2>\n<p><code>dns-prefetch</code> is the lightest hint. The browser looks up the IP for a hostname and caches the result. It does not open a socket or download anything.</p>\n<pre><code class=\"language-html\">&#x3C;link rel=\"dns-prefetch\" href=\"https://fonts.googleapis.com\">\n&#x3C;link rel=\"dns-prefetch\" href=\"https://api.example.com\">\n</code></pre>\n<p>Use it when you know you will contact an origin later but are not sure exactly when, or when <code>preconnect</code> would be wasteful (many origins, only one or two requests each). The cost is small; the win is avoiding DNS latency on the first request to that host.</p>\n<h2>preconnect</h2>\n<p><code>preconnect</code> goes further: DNS lookup, TCP handshake, and TLS negotiation all happen ahead of time. When the first real request to that origin fires, the connection is ready.</p>\n<pre><code class=\"language-html\">&#x3C;link rel=\"preconnect\" href=\"https://cdn.example.com\" crossorigin>\n</code></pre>\n<p>Add <code>crossorigin</code> when you will fetch CORS-enabled resources (fonts, images with CORS, fetch/XHR). Without it, the browser may open a connection that cannot be reused for credentialed or CORS requests.</p>\n<p><strong>Do not preconnect to everything.</strong> Each warm connection consumes memory and CPU on both client and server. Limit preconnect to a handful of origins that sit on your critical path—your CDN, your API, a font provider—not every third-party script on the page.</p>\n<h2>prefetch</h2>\n<p><code>prefetch</code> tells the browser to fetch a resource at low priority because it will likely be needed on a <strong>future</strong> navigation, not the current one. The response is stored in the HTTP cache (or discarded if cache policy does not allow storage).</p>\n<pre><code class=\"language-html\">&#x3C;link rel=\"prefetch\" href=\"/checkout\" as=\"document\">\n&#x3C;link rel=\"prefetch\" href=\"/assets/chunk-cart.js\" as=\"script\">\n</code></pre>\n<p>Good fits:</p>\n<ul>\n<li>The next step in a wizard after the user completes the current screen.</li>\n<li>A route bundle the user is likely to open (product detail from a listing page).</li>\n<li>Assets for a page linked prominently in the UI.</li>\n</ul>\n<p>Prefetch is speculative. If the user never navigates there, you spent bandwidth for nothing. Keep prefetches tied to strong signals—visible links, recent behavior, or explicit prerender/speculation rules—not blind guesses on every page.</p>\n<h2>preload</h2>\n<p><code>preload</code> is for the <strong>current</strong> navigation. It fetches a resource early with high priority so it is available when the parser or script actually needs it.</p>\n<pre><code class=\"language-html\">&#x3C;link rel=\"preload\" href=\"/fonts/inter-var.woff2\" as=\"font\" type=\"font/woff2\" crossorigin>\n&#x3C;link rel=\"preload\" href=\"/hero.webp\" as=\"image\">\n&#x3C;link rel=\"preload\" href=\"/critical.css\" as=\"style\">\n</code></pre>\n<p>The <code>as</code> attribute is required. It lets the browser set correct priority, apply content security policy, and know how to handle the response. Common values: <code>script</code>, <code>style</code>, <code>font</code>, <code>image</code>, <code>fetch</code>, <code>document</code>.</p>\n<p>Preload shines when:</p>\n<ul>\n<li>A resource is discovered late (background image in CSS, font referenced only after stylesheet parse).</li>\n<li>You split code and know the main chunk must run immediately.</li>\n<li>LCP depends on an image or font that would otherwise queue behind less important assets.</li>\n</ul>\n<p><strong>Caveat:</strong> Preloading the wrong file wastes bandwidth and can <em>hurt</em> performance by competing with truly critical resources. Preload only what you will use on this page load, and prefer one strong candidate over many weak ones.</p>\n<h2>modulepreload</h2>\n<p>For applications built with native ES modules, <code>modulepreload</code> fetches a module and optionally walks its static imports to preload the dependency graph.</p>\n<pre><code class=\"language-html\">&#x3C;link rel=\"modulepreload\" href=\"/assets/app.js\">\n</code></pre>\n<p>Bundlers like Vite and webpack can inject these automatically for entry chunks. Manual hints help when you know which module the user’s path will execute first.</p>\n<h2>HTTP Link headers</h2>\n<p>The same hints work as response headers, which is useful when HTML is generated dynamically or when a CDN can attach hints without changing page markup.</p>\n<pre><code>Link: &#x3C;https://cdn.example.com>; rel=preconnect; crossorigin\nLink: &#x3C;/assets/main.js>; rel=preload; as=script\n</code></pre>\n<p>Headers and <code>&#x3C;link></code> tags can coexist; avoid duplicating the same hint twice without reason.</p>\n<h2>Priority and interaction with the browser</h2>\n<p>Browsers schedule hinted work alongside normal parsing. Rough priority order (simplified):</p>\n<ol>\n<li><strong>preload</strong> (current page, high)—competes with parser-discovered critical resources; use sparingly.</li>\n<li>Normal document subresources (scripts, stylesheets, sync discoveries).</li>\n<li><strong>prefetch</strong> (future navigation, low)—runs when the network is idle.</li>\n</ol>\n<p>Because preload is high priority, overusing it can starve other critical downloads. Prefetch is deliberately deprioritized so it should not block the current page, but on slow networks or metered connections it still consumes data the user may never need.</p>\n<h2>Choosing the right hint</h2>\n<p>A practical decision flow:</p>\n<ol>\n<li><strong>Same page, need it soon for render or LCP?</strong> → <code>preload</code> (or <code>modulepreload</code> for ES modules).</li>\n<li><strong>Same page, but only DNS or connection setup is the bottleneck?</strong> → <code>preconnect</code> (or <code>dns-prefetch</code> if connection reuse is unlikely).</li>\n<li><strong>Next page or likely next navigation?</strong> → <code>prefetch</code> (or speculation rules for more advanced cases).</li>\n<li><strong>Many third-party hosts, one request each?</strong> → <code>dns-prefetch</code> only.</li>\n</ol>\n<p>When in doubt, measure. DevTools Network panel shows initiator type (<code>preload</code>, <code>prefetch</code>, etc.) and whether early hints actually moved the start time of the dependent request.</p>\n<h2>Common mistakes</h2>\n<p><strong>Preconnecting to unused origins.</strong> Audit hints after refactors; stale preconnects are pure overhead.</p>\n<p><strong>Preloading assets that are already high in the HTML.</strong> If <code>&#x3C;script src=\"app.js\"></code> is the first tag in <code>&#x3C;body></code>, a preload for the same URL adds duplicate fetch coordination work without benefit.</p>\n<p><strong>Missing <code>crossorigin</code> on fonts.</strong> Font requests are CORS-enabled; preload and preconnect must match the eventual request mode or the browser may fetch twice.</p>\n<p><strong>Prefetching without cache-friendly responses.</strong> Prefetch stores in HTTP cache. If <code>Cache-Control: no-store</code> applies, the prefetched copy may be unusable on navigation.</p>\n<p><strong>Treating prefetch as guaranteed.</strong> It is a hint. Slow networks, data saver mode, or memory pressure can cause the browser to skip or evict prefetched resources.</p>\n<h2>Beyond classic hints: Speculation Rules</h2>\n<p>Modern Chromium-based browsers support the <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Speculation_Rules_API\">Speculation Rules API</a>, which supersedes the older <code>rel=prerender</code> link hint. You define JSON rules for prefetching or prerendering URLs (including full document prerender for instant navigations). It is more flexible than a single <code>&#x3C;link rel=\"prefetch\"></code> but also easier to misuse; prerendering heavy pages can waste CPU and memory.</p>\n<p>Use speculation rules when you have high-confidence next navigations (same-origin, user hover or viewport signals). For simple “maybe they click this link” cases, <code>prefetch</code> remains enough.</p>\n<h2>Further reading</h2>\n<ul>\n<li><a href=\"https://www.w3.org/TR/resource-hints/\">Resource Hints</a>: W3C specification for dns-prefetch, preconnect, prefetch, and prerender.</li>\n<li><a href=\"https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/rel/preload\">preload on MDN</a>: Syntax, <code>as</code> values, and CORS notes.</li>\n<li><a href=\"https://web.dev/uses-rel-preconnect/\">Preconnect to required origins</a>: Lighthouse guidance and measurement.</li>\n<li><a href=\"https://css-tricks.com/prefetching-preloading-prebrowsing/\">Prefetching, preloading, prebrowsing</a>: Practical overview of when each hint fits.</li>\n<li><a href=\"https://developer.chrome.com/docs/web-platform/prerender-pages\">Speculation Rules API</a>: Prerender and prefetch with structured rules.</li>\n</ul>","frontmatter":{"date":"June 12, 2023","title":"Speed up page loads with Resource Hints","description":"Resource hints are declarative instructions in HTML that tell the browser to prepare for future navigation or fetch work early—DNS lookup, TCP/TLS handshake, or downloading a file—before the parser or JavaScript would normally discover the need. Used carefully, dns-prefetch, preconnect, prefetch, preload, and modulepreload can shave meaningful time off critical paths without changing application logic.","tags":["Resource hints","Performance","dns-prefetch","preconnect","preload","Page load performance"]}}},"pageContext":{"id":"6d7d08e0-4db3-56b1-9fc6-a0be1f942fe4"}},"staticQueryHashes":["4080856488"]}