HTTP Link Header Preload — Reduce LCP Without Changing Your HTML
Updated April 2026
Your HTML tells the browser what to load. The HTTP Link header tells it what to preload before it even reads the HTML. For fonts, hero images, and critical CSS, this difference translates directly into a faster Largest Contentful Paint.
How it works
When a browser receives an HTTP response, it reads the headers before parsing the body. If a Link header specifies a preload, the browser starts fetching that resource immediately — while still downloading and parsing the HTML. For a font that would normally be discovered only after the CSS is parsed, this saves hundreds of milliseconds.
The Link header syntax
# Preload a font Link: </fonts/inter.woff2>; rel=preload; as=font; crossorigin # Preload a hero image Link: </images/hero.webp>; rel=preload; as=image # Preload critical CSS Link: </css/critical.css>; rel=preload; as=style # Preload a script Link: </js/app.js>; rel=preload; as=script # Multiple resources — separate with comma Link: </fonts/inter.woff2>; rel=preload; as=font; crossorigin, </images/hero.webp>; rel=preload; as=image
Config by stack
Nginx
server { listen 443 ssl http2; server_name yourapp.com; location = / { # Add Link headers for your homepage's critical resources add_header Link "</fonts/inter.woff2>; rel=preload; as=font; crossorigin" always; add_header Link "</images/hero.webp>; rel=preload; as=image" always; add_header Link "</css/critical.css>; rel=preload; as=style" always; }
}
Vercel (vercel.json)
{ "headers": [ { "source": "/", "headers": [ { "key": "Link", "value": "</fonts/inter.woff2>; rel=preload; as=font; crossorigin, </images/hero.webp>; rel=preload; as=image" } ] } ]
}
Express / Node.js
app.get("/", (req, res) => { res.setHeader("Link", [ "</fonts/inter.woff2>; rel=preload; as=font; crossorigin", "</images/hero.webp>; rel=preload; as=image", "</css/critical.css>; rel=preload; as=style" ].join(", ")); res.sendFile("index.html");
});
Cloudflare (Transform Rules)
Rules → Transform Rules → Modify Response Headers → Set header: Link = your preload value. Apply to source matching your homepage path.
The as= attribute — get it right
| Resource type | as= value | Extra attributes |
|---|---|---|
| Font file (.woff2) | font | crossorigin (required even for same-origin fonts) |
| Image (.webp, .jpg, .png) | image | imagesrcset and imagesizes for responsive images |
| CSS file | style | None needed |
| JavaScript file | script | None needed |
| Video file | video | None needed |
HTTP/2 Server Push vs Link preload
HTTP/2 Server Push actively sent resources to the browser before it asked. It was deprecated and removed from Chrome in 2022 because it often pushed resources the browser already had cached. Link preload is better — the browser decides whether to fetch based on its cache state. Always prefer Link preload over Server Push.
Verify it is working
# Check headers are being sent curl -I https://yoursite.com/ | grep -i link # In DevTools Network tab: # Preloaded resources show "Initiator: Link" and appear before other resources # LCP resources should show fetchpriority="high"Run a live PageSpeed audit → SpeedFixer