HTTP

Header

Link Header

Learn how the Link header provides resource hints and enables preloading of CSS, fonts, and scripts to improve page load performance and user experience.

6 min read intermediate Try in Playground

TL;DR: Provides resource hints and relationships like preload, prefetch, and pagination. Enables browsers to optimize loading by fetching resources early.

The Link header provides relationships between the current resource and other resources. It’s commonly used for resource hints (preload, prefetch, preconnect) and pagination, enabling browsers to optimize loading and discover related resources.

Think of it as a way to tell the browser “while you’re processing this page, you’ll also need these other resources” or “here’s where to find the next page in a series.”

Server suggests resources to preload:

HTTP/1.1 200 OK
Content-Type: text/html
Link: </styles/main.css>; rel="preload"; as="style"
Link: </scripts/app.js>; rel="preload"; as="script"

<!DOCTYPE html>
<html>...
```text

**Browser preloads resources before parsing HTML:**

Browser starts downloading `main.css` and `app.js` immediately, improving page load time.

## Syntax

```http
Link: <uri-reference>; rel="relation-type"; param1="value1"; param2="value2"
Link: <uri1>; rel="relation1", <uri2>; rel="relation2"

Common Parameters

  • rel - Relationship type (required)
  • as - Resource type (for preload)
  • type - MIME type of the resource
  • crossorigin - CORS mode
  • title - Link title

Resource Hints

Preload (High Priority)

Link: </fonts/custom-font.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin
```text

Tells browser to download resource immediately as it's needed soon.

### Prefetch (Low Priority)

```http
Link: </pages/next-page.html>; rel="prefetch"

Hints that resource might be needed for future navigation.

Preconnect

Link: <https://api.example.com>; rel="preconnect"
Link: <https://cdn.example.com>; rel="preconnect"; crossorigin
```text

Establishes early connection to origin (DNS, TCP, TLS).

### DNS Prefetch

```http
Link: <https://analytics.example.com>; rel="dns-prefetch"

Performs DNS resolution early.

Prerender

Link: </next-page.html>; rel="prerender"
```text

Fully renders page in background (use cautiously, resource-intensive).

## Resource Types (as parameter)

### Stylesheets

```http
Link: </styles/main.css>; rel="preload"; as="style"
Link: </styles/print.css>; rel="preload"; as="style"; media="print"

Scripts

Link: </scripts/vendor.js>; rel="preload"; as="script"
Link: </scripts/app.js>; rel="preload"; as="script"; type="module"
```text

### Fonts

```http
Link: </fonts/roboto.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin

Always use crossorigin for fonts, even on same origin.

Images

Link: </images/hero.jpg>; rel="preload"; as="image"
Link: </images/logo.webp>; rel="preload"; as="image"; type="image/webp"
```text

### Videos

```http
Link: </videos/intro.mp4>; rel="preload"; as="video"

Fetch/XHR

Link: </api/data.json>; rel="preload"; as="fetch"; crossorigin
```text

## Pagination

### Next and Previous Pages

```http
Link: </blog/posts?page=2>; rel="next"
Link: </blog/posts?page=1>; rel="prev"

Helps search engines understand page relationships.

First and Last Pages

Link: </blog/posts?page=1>; rel="first"
Link: </blog/posts?page=50>; rel="last"
```text

### Canonical URL

```http
Link: <https://example.com/original-article>; rel="canonical"

Indicates the preferred version of a page.

Link: </styles/main.css>; rel="preload"; as="style",
      </scripts/app.js>; rel="preload"; as="script",
      </fonts/font.woff2>; rel="preload"; as="font"; crossorigin
```http

### Multiple Headers

```http
Link: </styles/main.css>; rel="preload"; as="style"
Link: </scripts/app.js>; rel="preload"; as="script"
Link: </fonts/font.woff2>; rel="preload"; as="font"; crossorigin

Both formats are valid and equivalent.

Real-World Scenarios

E-commerce Product Page

HTTP/1.1 200 OK
Content-Type: text/html
Link: </api/product/related>; rel="prefetch"
Link: </images/product-zoom.jpg>; rel="preload"; as="image"
Link: </scripts/product-viewer.js>; rel="preload"; as="script"
Link: <https://cdn.payment-provider.com>; rel="preconnect"
```http

Optimizes for common user actions (viewing related products, zooming images).

### Blog with Pagination

```http
HTTP/1.1 200 OK
Content-Type: text/html
Link: </blog?page=1>; rel="first"
Link: </blog?page=2>; rel="prev"
Link: </blog?page=4>; rel="next"
Link: </blog?page=25>; rel="last"
Link: <https://example.com/blog?page=3>; rel="canonical"

Single Page Application

HTTP/1.1 200 OK
Content-Type: text/html
Link: </api/user/profile>; rel="preload"; as="fetch"; crossorigin
Link: </chunks/dashboard.js>; rel="prefetch"
Link: </chunks/settings.js>; rel="prefetch"
Link: <https://api.example.com>; rel="preconnect"
```http

Preloads critical data, prefetches likely route chunks.

### Web Font Optimization

```http
HTTP/1.1 200 OK
Content-Type: text/html
Link: </fonts/roboto-regular.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin
Link: </fonts/roboto-bold.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin
Link: </fonts/icons.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin

Eliminates font loading delay.

Server Implementation

Node.js (Express)

const express = require('express')
const app = express()

// Add resource hints
app.get('/', (req, res) => {
  res.set('Link', [
    '</styles/main.css>; rel="preload"; as="style"',
    '</scripts/app.js>; rel="preload"; as="script"',
    '</fonts/font.woff2>; rel="preload"; as="font"; type="font/woff2"; crossorigin'
  ])
  res.sendFile('index.html')
})

// Pagination headers
app.get('/api/posts', (req, res) => {
  const page = parseInt(req.query.page) || 1
  const totalPages = 100

  const links = []
  if (page > 1) {
    links.push(`</api/posts?page=${page - 1}>; rel="prev"`)
  }
  if (page < totalPages) {
    links.push(`</api/posts?page=${page + 1}>; rel="next"`)
  }
  links.push(`</api/posts?page=1>; rel="first"`)
  links.push(`</api/posts?page=${totalPages}>; rel="last"`)

  res.set('Link', links)
  res.json({ posts: getPosts(page) })
})
```nginx

### Nginx

```nginx
location / {
    add_header Link '</styles/main.css>; rel="preload"; as="style"';
    add_header Link '</scripts/app.js>; rel="preload"; as="script"';
    add_header Link '</fonts/font.woff2>; rel="preload"; as="font"; crossorigin';
}

# For specific routes
location /product {
    add_header Link '<https://cdn.example.com>; rel="preconnect"';
    add_header Link '</api/product/related>; rel="prefetch"';
}

Apache

<FilesMatch "\.(html|php)$">
    Header add Link "</styles/main.css>; rel=\"preload\"; as=\"style\""
    Header add Link "</scripts/app.js>; rel=\"preload\"; as=\"script\""
    Header add Link "</fonts/font.woff2>; rel=\"preload\"; as=\"font\"; crossorigin"
</FilesMatch>
```javascript

### Python (Flask)

```python
from flask import Flask, Response, jsonify

app = Flask(__name__)

@app.route('/')
def index():
    response = Response(render_template('index.html'))
    response.headers.add('Link', '</styles/main.css>; rel="preload"; as="style"')
    response.headers.add('Link', '</scripts/app.js>; rel="preload"; as="script"')
    response.headers.add('Link', '</fonts/font.woff2>; rel="preload"; as="font"; crossorigin')
    return response

@app.route('/api/posts')
def posts():
    page = int(request.args.get('page', 1))
    total_pages = 100

    response = jsonify({'posts': get_posts(page)})

    if page > 1:
        response.headers.add('Link', f'</api/posts?page={page-1}>; rel="prev"')
    if page < total_pages:
        response.headers.add('Link', f'</api/posts?page={page+1}>; rel="next"')

    return response

HTML Equivalent

Link headers have HTML equivalents:

Preload Header

Link: </styles/main.css>; rel="preload"; as="style"
```text

### HTML Equivalent

```html
<link rel="preload" href="/styles/main.css" as="style" />

When to Use Which

Use Link Header when:

  • Resource is critical for initial render
  • You want browser to start downloading before HTML parsing
  • Resource applies to all pages (can set in server config)

Use HTML <link> when:

  • Resource is page-specific
  • You need JavaScript to determine the resource
  • You want better developer visibility

Best Practices

For Preload

1. Only preload critical resources

# ✅ Critical CSS
Link: </styles/critical.css>; rel="preload"; as="style"

# ❌ Don't preload everything
Link: </styles/print.css>; rel="preload"; as="style"
```text

**2. Specify resource type**

```http
# ✅ Include 'as' attribute
Link: </fonts/font.woff2>; rel="preload"; as="font"; crossorigin

# ❌ Missing 'as' attribute
Link: </fonts/font.woff2>; rel="preload"

3. Use crossorigin for fonts

# ✅ Always use crossorigin for fonts
Link: </fonts/font.woff2>; rel="preload"; as="font"; crossorigin

# ❌ Missing crossorigin (font won't load)
Link: </fonts/font.woff2>; rel="preload"; as="font"
```http

### For Preconnect

**1. Limit preconnects**

```http
# ✅ Only critical origins
Link: <https://api.example.com>; rel="preconnect"

# ❌ Too many preconnects (wastes resources)
Link: <https://origin1.com>; rel="preconnect"
Link: <https://origin2.com>; rel="preconnect"
Link: <https://origin3.com>; rel="preconnect"
Link: <https://origin4.com>; rel="preconnect"

2. Use dns-prefetch as fallback

Link: <https://api.example.com>; rel="preconnect"
Link: <https://analytics.example.com>; rel="dns-prefetch"
```http

### For Pagination

**1. Always include rel="canonical"**

```http
Link: <https://example.com/blog?page=3>; rel="canonical"
Link: </blog?page=2>; rel="prev"
Link: </blog?page=4>; rel="next"

2. Use absolute URLs for SEO

# ✅ Absolute URLs
Link: <https://example.com/blog?page=2>; rel="prev"

# ⚠️ Relative (works but less ideal for SEO)
Link: </blog?page=2>; rel="prev"
```text

## Performance Impact

### Without Link Header

```text
1. Browser requests HTML
2. Browser parses HTML
3. Browser discovers <link> for CSS
4. Browser requests CSS
5. Browser discovers @font-face
6. Browser requests font
```text

### With Link Header

```text
1. Browser requests HTML (receives Link headers)
2. Browser starts downloading CSS and font immediately
3. Browser parses HTML (resources already loading)
4. Faster render time
```text

## Common Issues

### Preload Not Used Warning

```http
# ❌ Preloaded but never used
Link: </unused.js>; rel="preload"; as="script"

Causes console warning and wastes bandwidth.

Wrong Resource Type

# ❌ Wrong 'as' value
Link: </styles/main.css>; rel="preload"; as="script"

# ✅ Correct 'as' value
Link: </styles/main.css>; rel="preload"; as="style"
```text

### Missing crossorigin for Fonts

```http
# ❌ Font won't load (CORS issue)
Link: </fonts/font.woff2>; rel="preload"; as="font"

# ✅ Includes crossorigin
Link: </fonts/font.woff2>; rel="preload"; as="font"; crossorigin

Browser Support

Link header is well-supported in modern browsers:

  • Preload: Chrome 50+, Firefox 85+, Safari 11.1+
  • Prefetch: Chrome 8+, Firefox 3.5+, Safari 13+
  • Preconnect: Chrome 46+, Firefox 39+, Safari 11.1+

Check caniuse.com for current support.

Frequently Asked Questions

What is the Link header?

Link provides metadata about related resources, similar to HTML link elements. Common uses include preloading resources, pagination links, and canonical URLs.

How do I preload resources with Link?

Use Link: </style.css>; rel=preload; as=style to preload CSS. The browser fetches it early, improving page load. Specify as= for correct priority.

Can I use multiple Link headers?

Yes, use multiple Link headers or combine in one with commas: Link: </a.css>; rel=preload, </b.js>; rel=preload. Both approaches work.

What is the difference between preload and prefetch?

preload fetches resources needed for current page with high priority. prefetch fetches resources for future navigation with low priority.

Keep Learning