Performance · Concept
Resource hints (preload and preconnect)
Published
Resource hints are <link> relations in <head> that start work before the parser would
discover the need for it: preload fetches one resource the current page will use, modulepreload
does the same for an ES module and its dependencies, preconnect opens a connection to an origin
without fetching, dns-prefetch resolves only the name, and prefetch fetches a resource for a
later navigation at low priority. In a PWA they shorten first visits, where the service worker
has not yet cached anything.
How it works
Section titled “How it works”The preload scanner finds <link> hints early in the HTML and queues the work at the priority
implied by the as type: as="style" is fetched at the highest priority, as="font" and
as="script" high, as="image" at the image’s usual priority unless fetchpriority says
otherwise. A preloaded response waits in the memory cache for the real request, which must match
the preload’s URL, destination, and CORS mode; a mismatch means two fetches
(Preload critical assets, web.dev).
Attributes that decide whether the preload is used
Section titled “Attributes that decide whether the preload is used”as. Required. Without it the fetch is treated like anXMLHttpRequestwith the wrong priority and the wrongAcceptheader, and it does not match the later request.crossorigin. Fonts are fetched in anonymous CORS mode from any origin, so a font preload needscrossorigineven for a same-origin file; a<script crossorigin>or afetch()likewise needs a matchingcrossoriginon the preload.type. Lets the browser skip the preload for a format it does not support, which is how a WOFF2 preload stays harmless in an engine that would use the WOFF fallback.
Which hint for which problem
Section titled “Which hint for which problem”preconnect pays for itself when a cross-origin request is certain and soon (a font host, the
API origin); each connection costs a socket, so more than a handful is counterproductive, and
dns-prefetch is the cheaper hint for the rest. modulepreload is the preload for import()
chunks the page will need at startup, and it also links the module so evaluation starts
sooner. prefetch is for the next navigation, not this page, and is superseded for documents
by speculation rules.
Support position
Section titled “Support position”preload shipped in Chrome 50 and Safari 11.1; Firefox enabled it in 56, disabled it again in
57 over web compatibility problems, and shipped it for good in 85 (BCD html.elements.link.rel.preload,
bug 1405761). preconnect is in Chrome 46, Firefox 39, Safari 11.1; modulepreload in Chrome
66, Firefox 115, Safari 17; prefetch is in Chromium and Firefox and behind a flag in Safari.
An unsupported hint is ignored, so the page loads the same way minus the head start.
Examples
Section titled “Examples”The markup example is the common case; the script examples cover hints added at runtime.
Preloading the web font the first paint needs
Section titled “Preloading the web font the first paint needs”The font is discovered only after the stylesheet is parsed; the hint starts it with the HTML.
crossorigin is required or Chrome fetches it a second time for the @font-face request.
<link rel="preload" href="/fonts/brand-sans.woff2" as="font" type="font/woff2" crossorigin><link rel="preconnect" href="https://api.example.com"><link rel="modulepreload" href="/scripts/app.3f2a1c.js">The preconnect warms the API origin the shell will call after it renders; the modulepreload
starts the main chunk and its imports before the module script tag is reached.
Adding a hint from script
Section titled “Adding a hint from script”A hint inserted at runtime, for instance when a route becomes likely, behaves like one in the
HTML. Set as and crossOrigin before href so the fetch starts with the right parameters.
function preloadFont(href) { const link = document.createElement('link'); link.rel = 'preload'; link.as = 'font'; link.type = 'font/woff2'; link.crossOrigin = 'anonymous'; link.href = href; document.head.append(link);}A preload that the page does not use triggers the console warning described below, so insert hints only for resources the current page will request.
Detecting support for a relation
Section titled “Detecting support for a relation”link.relList.supports() reports whether the engine knows a relation, which is the test to
run before relying on modulepreload or prefetch; the fallback is to do nothing, because the
real request still happens later.
function supportsRel(rel) { const link = document.createElement('link'); return 'relList' in link && typeof link.relList.supports === 'function' && link.relList.supports(rel);}
if (supportsRel('modulepreload')) { preloadModule('/scripts/editor.3f2a1c.js');} else { // unsupported: the import() will fetch the chunk when it runs}supports() answers from the engine’s relation list, not from a network test, so it is cheap
enough to call per hint.
See also
Section titled “See also”- rel=preload (developer.mozilla.org)
- Preload critical assets to improve loading speed (web.dev)
- link.json in browser-compat-data (github.com)
- Font and image optimization
- Speculation Rules API
- Code splitting with dynamic import()
Specifications
| Specification | Status |
|---|---|
| None. | |