Resource Hints: Preload & Prefetch for Faster Loading

Medium

preload

Current-navigation critical assets

  • - High priority fetch
  • - Overuse can compete with core resources

prefetch

Likely-future navigation

  • - Low-priority/speculative
  • - May be skipped under contention

preconnect

Critical cross-origin setup

  • - DNS + TCP + TLS early
  • - Use for truly important origins

dns-prefetch

Lighter warm-up

  • - DNS only
  • - Lower cost than full preconnect

Core Lens

Hints are priority control. The win comes from loading the right thing early, not preloading everything.

Flow

Classify resource
Assign hint
Validate priority
Measure impact

Resource hints are scheduling hints to the browser network stack. Interview-safe explanations map preload vs prefetch vs preconnect; deeper explanations include priority trade-offs, speculative behavior, and cache/reuse requirements (such as matching attributes and CORS for fonts).

Quick Decision Guide

Quick Guide:

Preload = "Load this now for current page" (high priority) - Fonts, hero images, critical CSS/JS - <link rel="preload" href="font.woff2" as="font" crossorigin>

Prefetch = "Load this for next page" (low priority) - Next page JavaScript, likely navigation targets - <link rel="prefetch" href="/dashboard.js">

Preconnect = "Connect to this domain early" - External APIs, CDNs, third-party domains - <link rel="preconnect" href="https://api.example.com">

Rule: Preload a small number of truly critical resources. Preloading too much defeats the purpose.

Interview-safe vs Deeper Browser Model

Interview-safe model

Use this quick mapping:

preload: fetch for current navigation (high importance)
prefetch: fetch for likely future navigation (low priority/speculative)
preconnect: set up DNS/TCP/TLS early for critical cross-origin dependencies
dns-prefetch: DNS only, cheaper than preconnect

Deeper browser model

For stronger answers, add:

preload competes with other critical requests, so overusing it can hurt
prefetch is opportunistic and may be skipped under data-saving or contention conditions
fonts often need crossorigin on preload for correct reuse
as should match resource type so prioritization and reuse work correctly

Practical framing

Resource hints are not speed hacks by default. They are priority control.

Use hints only when you can justify which user-visible bottleneck they remove.

Preload - Critical Resources

What is Preload?

Preload tells browser: "Download this now, I need it soon"

<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero.jpg" as="image">
<link rel="preload" href="font.woff2" as="font" crossorigin>

When to Preload

Critical fonts - Prevents FOUT/FOIT

<link rel="preload" href="/fonts/inter.woff2" as="font" type="font/woff2" crossorigin>

Hero images - Above-the-fold images

<link rel="preload" href="/hero.jpg" as="image">

Critical CSS - Required for first paint

<link rel="preload" href="/critical.css" as="style">

Critical JavaScript - App initialization code

<link rel="preload" href="/app.js" as="script">

Important Attributes

as: Resource type (font, image, script, style, fetch)
type: MIME type (font/woff2, image/webp)
crossorigin: Required for fonts and CORS requests
<link 
  rel="preload" 
  href="font.woff2" 
  as="font" 
  type="font/woff2" 
  crossorigin
>

Prefetch - Future Resources

What is Prefetch?

Prefetch tells browser: "Load this when idle, I'll need it later"

<link rel="prefetch" href="/next-page.js">
<link rel="prefetch" href="/dashboard-data.json">

When to Prefetch

Next page - Likely navigation destination

<link rel="prefetch" href="/dashboard">

Future route bundles - Code for next page

<link rel="prefetch" href="/chunks/dashboard.js">

API data - Fetch data user will likely need

<link rel="prefetch" href="/api/user/profile">

Dynamic Prefetching

// Prefetch on hover
function PrefetchLink({ href, children }) {
  const handleMouseEnter = () => {
    const link = document.createElement('link');
    link.rel = 'prefetch';
    link.href = href;
    document.head.appendChild(link);
  };
  
  return (
    <a href={href} onMouseEnter={handleMouseEnter}>
      {children}
    </a>
  );
}

React Implementation

import Head from 'next/head';

function Page() {
  return (
    <>
      <Head>
        {/* Prefetch next likely page */}
        <link rel="prefetch" href="/dashboard.js" />
      </Head>
      <a href="/dashboard">Go to Dashboard</a>
    </>
  );
}

Preconnect & DNS-Prefetch

Preconnect

Establish early connection to external domains.

<!-- Connect to API domain -->
<link rel="preconnect" href="https://api.example.com">

<!-- Connect to CDN -->
<link rel="preconnect" href="https://cdn.example.com">

<!-- Google Fonts (need both) -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>

DNS-Prefetch

Resolve DNS early (lighter than preconnect).

<!-- Just DNS lookup, no connection -->
<link rel="dns-prefetch" href="https://analytics.com">

When to Use Each

<!-- High priority: preconnect -->
<link rel="preconnect" href="https://api.example.com">

<!-- Lower priority: dns-prefetch -->
<link rel="dns-prefetch" href="https://analytics.com">

Preconnect = DNS + TCP + TLS (full connection)

DNS-Prefetch = DNS only (faster but less complete)

Best Practices

What to Preload

Do Preload:

1-2 critical fonts
Hero/LCP image
Critical CSS (if external)
Essential first-paint JS

Don't Preload:

Everything (defeats purpose)
Below-fold resources
Non-critical assets
More than 3-4 resources

Preload Example

<head>
  <!-- Preload only critical resources -->
  <link rel="preload" href="/fonts/inter-bold.woff2" as="font" crossorigin>
  <link rel="preload" href="/hero.webp" as="image">
  
  <!-- Regular resources -->
  <link rel="stylesheet" href="/styles.css">
  <script defer src="/app.js"></script>
</head>

What to Prefetch

Do Prefetch:

Next page JS chunks
Likely navigation targets
Search results
User profile data

Don't Prefetch:

All possible pages
Heavy resources
Rarely accessed content

Common Mistakes

<!-- ❌ Bad: Preload everything -->
<link rel="preload" href="image1.jpg" as="image">
<link rel="preload" href="image2.jpg" as="image">
<link rel="preload" href="image3.jpg" as="image">
<!-- Too many, slows down critical resources -->

<!-- ✅ Good: Preload only critical -->
<link rel="preload" href="hero.jpg" as="image">

<!-- ❌ Bad: Missing 'as' attribute -->
<link rel="preload" href="style.css">

<!-- ✅ Good: Include 'as' attribute -->
<link rel="preload" href="style.css" as="style">

<!-- ❌ Bad: Preload but never use -->
<link rel="preload" href="unused.js" as="script">
<!-- Browser warning: preload not used -->

<!-- ✅ Good: Preload and use -->
<link rel="preload" href="app.js" as="script">
<script src="app.js"></script>