Skip to content

Link Headers

DodaTech 2 min read

title: "Link Headers — HTTP Header Pagination with rel=next/prev" description: "Link headers provide pagination navigation via HTTP response headers with rel values (next, prev, first, last) following RFC 5988 for web linking." date: 2026-06-28 lastmod: 2026-06-28 weight: 20 tags: [apis, pagination] }

Link headers provide pagination navigation through HTTP response headers using Link header with rel values like next, prev, first, and last.

What You'll Learn

  • RFC 5988 web linking for pagination
  • Parsing Link headers on the client
  • Combining Link headers with body metadata

Why It Matters

Link headers are the standard way to provide pagination URLs without cluttering the response body, as used by GitHub, GitLab, and many major APIs.

Code Examples

# Link header pagination
@app.route('/users')
def list_users():
    page = request.args.get('page', 1, type=int)
    per_page = min(request.args.get('per_page', 30, type=int), 100)
    offset = (page - 1) * per_page

    total = db.count_users()
    total_pages = (total + per_page - 1) // per_page

    users = db.get_users(limit=per_page, offset=offset)

    # Build Link header
    links = []
    base_url = f"{request.base_url}?per_page={per_page}"

    links.append(f'<{base_url}&page=1>; rel="first"')
    if page > 1:
        links.append(f'<{base_url}&page={page-1}>; rel="prev"')
    if page < total_pages:
        links.append(f'<{base_url}&page={page+1}>; rel="next"')
    links.append(f'<{base_url}&page={total_pages}>; rel="last"')

    response = jsonify({"data": [u.to_dict() for u in users]})
    response.headers['Link'] = ', '.join(links)
    response.headers['X-Total-Count'] = str(total)
    return response
// Client parsing Link header
function parseLinkHeader(header) {
  if (!header) return {};
  return header.split(',').reduce((links, part) => {
    const match = part.match(/<([^>]+)>;\s*rel="([^"]+)"/);
    if (match) links[match[2]] = match[1];
    return links;
  }, {});
}

// Usage
const res = await fetch('/users?page=2');
const links = parseLinkHeader(res.headers.get('link'));
console.log('Next page:', links.next);
console.log('Last page:', links.last);

Common Mistakes

Without Link headers, clients must construct URLs manually.

2. Missing rel Values

Every link needs a rel attribute telling clients what it represents.

3. Incorrect First/Last URLs

Always include first and last links for full navigation.

Pick one. GitHub uses Link headers; use body links for simpler client access.

5. Not Including Total Count

Add X-Total-Count header so clients know total results.

Practice Questions

  1. What RFC defines web linking for pagination?
  2. What are the standard rel values for pagination?
  3. How do clients parse Link headers?
  4. Why does GitHub use Link headers instead of body metadata?
  5. How do you include total count without Link headers?

Answers:

  1. RFC 5988.
  2. first, prev, next, last.
  3. Split by comma, parse URL and rel from each segment.
  4. Clean response body, standardized, cache-friendly.
  5. Using a custom header like X-Total-Count or X-Total-Pages.

Challenge: Implement Link header pagination for an API. Write both the server that generates Link headers and the client that parses them for navigation.

FAQ

Should I use Link headers or body metadata?

: Link headers are standard but less discoverable. Many APIs use both.

Can I use Link headers with cursor pagination?

: Yes. GitHub uses Link headers with cursor pagination.

What if there are multiple `rel="next"` links?

: There should be only one per relation type.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro