HttpFixerBlogCache → HTTP Redirect Chains
Performance

HTTP Redirect Chains: Why They Happen and How to Fix Them

Updated April 2026

Redirect chain on your site? Check it now. Redirect Chain Checker →

A redirect chain is when URL A redirects to URL B which redirects to URL C before reaching the destination. Each extra hop adds latency, wastes crawl budget, and bleeds PageRank. The fix is always the same: collapse to a single direct redirect.

What causes redirect chains

Detect your redirect chain

# Follow all redirects and show each hop
curl -sI -L https://example.com | grep -E "HTTP/|Location:"

# Example — 3-hop chain:
# HTTP/1.1 301 Moved Permanently
# Location: https://example.com/
# HTTP/1.1 301 Moved Permanently
# Location: https://www.example.com/
# HTTP/1.1 200 OK

Fix redirect chains — by stack

Nginx

# Wrong — two server blocks creating a chain
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://example.com$request_uri;
}
server {
    listen 443 ssl;
    server_name www.example.com;
    return 301 https://example.com$request_uri;  # chain!
}

# Right — one block handles both HTTP and www in one hop
server {
    listen 80;
    listen 443 ssl;
    server_name www.example.com;
    return 301 https://example.com$request_uri;
}
server {
    listen 443 ssl;
    server_name example.com;
    # canonical — no redirect
}

Cloudflare

# Wrong: separate rule for HTTP→HTTPS + separate rule for www→non-www = two hops
# Right: one Redirect Rule handles both

# Rules → Redirect Rules → Create Rule
# When: (http.host eq "www.example.com") or (http.scheme eq "http")
# Then: https://example.com${http.request.uri.path} — 301

# Gotcha: "Always Use HTTPS" + a Page Rule for HTTPS = chain
# Pick one. Disable the Page Rule and use "Always Use HTTPS" alone.

Vercel

// vercel.json
{
  "redirects": [
    {
      "source": "/old-page",
      "destination": "/new-page",
      "permanent": true
    }
  ]
}
// If /old-page → /intermediate and /intermediate → /new-page both exist:
// Add /old-page → /new-page directly and remove /old-page → /intermediate

Apache

# Wrong — multiple RewriteRules creating hops
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\. [NC]
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]

# Right — one rule handles both www and HTTP
RewriteEngine On
RewriteCond %{HTTP_HOST} ^www\.example\.com$ [OR]
RewriteCond %{HTTPS} off
RewriteRule ^ https://example.com%{REQUEST_URI} [R=301,L]

Next.js

// next.config.js
module.exports = {
  async redirects() {
    return [
      {
        source: '/old-path',
        destination: '/final-destination',  // skip any intermediate
        permanent: true,
      },
    ]
  },
}

The most common chain — HTTP + www

http://www.example.com
  → https://www.example.com   (HTTP→HTTPS — hop 1)
  → https://example.com       (www→non-www — hop 2)
  → 200 OK                    (destination)

Fix: send http://www.example.com/* directly to https://example.com/*
One rule. One hop.
Cloudflare: "Always Use HTTPS" adds an automatic HTTP→HTTPS redirect. If you also have a Page Rule for HTTP — you have a chain. Disable the Page Rule and let "Always Use HTTPS" handle it alone.

Redirect chains vs redirect loops

TypeWhat happensBrowser errorFix
Redirect chainA → B → C → destinationSlow load, no errorCollapse to A → destination
Redirect loopA → B → A (infinite)ERR_TOO_MANY_REDIRECTSFind the circular rule, remove it

SEO and performance impact

Verify the fix

# Should now show one hop maximum
curl -sI -L http://www.example.com | grep -E "HTTP/|Location:"
# HTTP/1.1 301 Moved Permanently
# Location: https://example.com/
# HTTP/1.1 200 OK
Check your redirect chain → Redirect Chain Checker
Visualise your full redirect chain with status codes → Redirect Chain Checker