Resource Hints — preload
Tell the browser about a critical resource early so it fetches at high priority instead of late.
preload is for a different problem than preconnect. Preconnect warms a connection; preload fetches an actual resource early — specifically a critical, late-discovered one the preload scanner can't see in the initial HTML. It's the go-to fix for a slow LCP caused by a CSS-referenced image or font.
Late-discovered resources
When HTML streams in, the preload scanner races ahead and starts fetching anything it can see in the markup. But some critical resources are invisible to it because they're referenced from other files:
- Fonts — declared via
@font-faceinside CSS. The browser must download + parse the CSS before it even knows the font exists. - Background images — set with
background-image: url(...)in CSS. Same late discovery — and if it's your LCP, that's a direct hit to the score.
preload short-circuits this: you put a hint in the HTML so the scanner fetches the resource immediately, in parallel, instead of waiting for the chain that would normally reveal it.
Preload the LCP image
Here's a hero image referenced from CSS. Without preload it can't start until the stylesheet is parsed; with preload it loads alongside the CSS and is ready before the stylesheet even finishes. Watch the LCP marker jump:
The syntax: as & crossorigin
<link rel="preload" href="/hero.webp" as="image" fetchpriority="high">
<link rel="preload" href="/fonts/Inter.woff2" as="font" type="font/woff2" crossorigin>as tells the browser the resource type (image, font, script…). Get it wrong and the browser can't match the preload to the real request, so it fetches the file twice. crossorigin is required for fonts (and any CORS resource) — omit it and, again, you get a double fetch.Preloading split bundles
Remember the emoji-picker chunk from bundle splitting? Normally the browser only discovers it needs that chunk after the main script runs. If it's actually critical, you can preload it so it fetches in parallel with the main bundle. With Webpack you don't even hand-write the link — magic comments generate it:
import(
/* webpackPreload: true */
"./EmojiPicker"
);
// Webpack emits <link rel="preload"> so the chunk loads alongside main.jsDon't block the parser
preload raises a resource's priority — but for scripts you must make sure the high-priority fetch doesn't turn into the parser waiting on it. The common pattern is to preload and mark the script async/defer, so it downloads early but doesn't stall rendering. And preload is a trade-off: pulling one resource forward can push others back, so reserve it for genuinely critical, late-discovered ones.
as value cause a double fetch?- →preload fetches a critical, late-discovered resource early (fonts, CSS background/LCP images).
- →It can dramatically improve LCP by loading the hero in parallel with the CSS.
- →Set
ascorrectly and addcrossoriginfor fonts — or you get a double fetch. - →You can preload split bundles too (Webpack magic comments).
- →For scripts, pair preload with
async/deferso it doesn't block the parser.