Setting up preload, prefetch and preconnect
Resource Hints let browser start loading resources ahead — before parser finds them. Proper use reduces LCP and FCP by 200–800 ms.
Three directives and purposes
| Directive | When | What it does |
|---|---|---|
preconnect |
ASAP | DNS + TCP + TLS to domain |
preload |
Current page | Load resource with high priority |
prefetch |
Next page | Load in background with low priority |
preconnect — eliminate connection overhead
<head>
<!-- Critical third-party domains — establish connection early -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="preconnect" href="https://cdn.example.ru" crossorigin>
<!-- API server if on different domain -->
<link rel="preconnect" href="https://api.example.ru">
<!-- dns-prefetch: DNS only, no TCP (for less critical) -->
<link rel="dns-prefetch" href="https://analytics.google.com">
<link rel="dns-prefetch" href="https://mc.yandex.ru">
</head>
crossorigin needed for CORS resources (fonts, JSON API, cross-domain images).
preload — priority loading for current page
<head>
<!-- LCP image — most important preload -->
<link rel="preload" as="image"
href="/images/hero.webp"
imagesrcset="/images/hero-640.webp 640w, /images/hero-1280.webp 1280w"
imagesizes="100vw">
<!-- Custom font -->
<link rel="preload" as="font" type="font/woff2"
href="/fonts/inter-regular.woff2" crossorigin>
<!-- Critical JS module (not defer/async) -->
<link rel="preload" as="script" href="/js/checkout.js">
<!-- CSS (if not in <head> directly) -->
<link rel="preload" as="style" href="/css/above-fold.css"
onload="this.onload=null;this.rel='stylesheet'">
</head>
Resource types for as: image, script, style, font, fetch, document, track, audio, video.
prefetch — preload next page
<!-- On cart page — prefetch checkout page -->
<link rel="prefetch" href="/checkout">
<link rel="prefetch" as="script" href="/js/checkout.chunk.js">
<link rel="prefetch" as="style" href="/css/checkout.css">
Browser loads prefetch resources in background with low priority — only when main resources loaded.
Dynamic prefetch on hover
// Prefetch on link hover (React)
function usePrefetch() {
const prefetched = useRef(new Set<string>());
return useCallback((url: string) => {
if (prefetched.current.has(url)) return;
prefetched.current.add(url);
const link = document.createElement('link');
link.rel = 'prefetch';
link.href = url;
document.head.appendChild(link);
}, []);
}
function NavLink({ to, children }: { to: string; children: React.ReactNode }) {
const prefetch = usePrefetch();
return (
<Link
to={to}
onMouseEnter={() => prefetch(to)}
onFocus={() => prefetch(to)}
>
{children}
</Link>
);
}
Speculation Rules API (Chrome 108+)
Modern alternative to prefetch — allows browser to fully pre-render page:
<script type="speculationrules">
{
"prerender": [
{
"where": {
"and": [
{ "href_matches": "/products/*" },
{ "not": { "href_matches": "/api/*" } }
]
},
"eagerness": "moderate"
}
],
"prefetch": [
{
"urls": ["/checkout", "/cart"],
"eagerness": "eager"
}
]
}
</script>
eagerness values: immediate (now), eager (on hover), moderate (on interaction), conservative (browser choice).
Early Hints (103)
Server sends preload headers before forming main response — while PHP/Laravel generates HTML, browser already starts loading resources:
# Nginx with http_v2_module
location / {
http2_push /css/app.css;
http2_push /js/app.js;
http2_push /fonts/inter.woff2;
# or via 103 Early Hints
}
// Laravel: send 103 Early Hints
public function show(): Response
{
// Send hints before rendering
header('Link: </css/app.css>; rel=preload; as=style, </js/app.js>; rel=preload; as=script', false, 103);
return response()->view('pages.product');
}
Preload mistakes
- Preload unused resource — browser warns in console
- Preload font without
crossorigin— loads twice - Too many preloads — compete for bandwidth, lower LCP image priority
- Preload + lazy on same image — mutually exclusive
Setup time: 4–8 hours for audit and proper hints.







