Performance Hints in Markup

The browser's preload scanner reads ahead in your HTML and starts downloads early, but it cannot know that the hero image is named in a CSS file, that a font lives on another origin, or that most visitors click "Pricing" next. A few attributes tell it. Used sparingly, they speed up Largest Contentful Paint and can make the next navigation instant; overused, they steal bandwidth from what the page needs (Core Web Vitals measures the results).

Script loading: async and defer

A plain <script src> stops the HTML parser while the file downloads and runs. defer downloads in parallel and runs the scripts in document order after parsing finishes, just before DOMContentLoaded. async also downloads in parallel but runs each script the moment it arrives, in no guaranteed order. Module scripts (type="module") are deferred by default. Neither attribute affects inline classic scripts.

How a classic, deferred and async script share time with the HTML parser
How a classic, deferred and async script share time with the HTML parser

Use defer (or a module) for application code that touches the DOM, and async for independent scripts such as analytics that must not wait for, or be waited on by, anything else.

Resource hints
Resource hints and priority attributes
Hint What the browser does Baseline status
dns-prefetch Resolves a host name early Newly available (2025)
preconnect Opens DNS + TCP + TLS to an origin Widely available
preload Fetches a file this page needs, at high priority Widely available
modulepreload Fetches and compiles a module and its imports Widely available
prefetch Fetches a likely next-page file at low priority Limited: not in Safari 10
fetchpriority Raises or lowers a single request's priority Newly available (2024)
Head hints for a page with a Google Font, a CSS background hero and a module appHTML
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="dns-prefetch" href="https://analytics.example.com">
<link rel="preload" href="/img/hero.avif" as="image" type="image/avif" fetchpriority="high">
<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>
<link rel="modulepreload" href="/js/chart.js"><!-- imported by app.js -->
<link rel="prefetch" href="/js/checkout.js">
<script type="module" src="/js/app.js"></script>
<script async src="https://analytics.example.com/tag.js"></script>

preload needs as so the browser applies the right priority, headers and cache key, and fonts need crossorigin even on your own origin because fonts are always fetched in CORS mode; a mismatch downloads the file twice. Chrome 1 warns in the console when a preloaded file is still unused about 3 seconds after load. An <img> already in the HTML needs no preload, just fetchpriority="high". Limit preconnect to the two or three origins you certainly use.

Speculation Rules

The Speculation Rules API goes further than prefetch: a JSON block tells the browser which pages to fetch, or fully prerender in a hidden tab, before the user clicks. When the click comes, the prerendered page is swapped in and appears instantly.

Prerendering same-site links on hover, but never the logout linkHTMLLive
<script type="speculationrules">
{
  "prerender": [{
    "where": { "and": [
      { "href_matches": "/*" },
      { "not": { "href_matches": "/logout" } },
      { "not": { "selector_matches": "[rel~=nofollow]" } }
    ] },
    "eagerness": "moderate"
  }],
  "prefetch": [{ "urls": ["/pricing"] }]
}
</script>

where rules match links in the document; urls rules list addresses and start immediately by default. The eagerness levels in Chrome on desktop are conservative (on pointer down), moderate (after a 200 ms hover), eager (10 ms hover) and immediate; on mobile, Chrome uses viewport heuristics instead of hover. Chrome keeps at most two hover-triggered speculations, discarding the oldest.

Check support with HTMLScriptElement.supports("speculationrules"), and watch speculations succeed or fail in DevTools under Application > Background services > Speculative loads.