How URL Redirects Work (Under the Hood)
How URL redirects work end-to-end: the HTTP request, the 3xx status, the Location header, browser caching, edge redirects, chains, and how to debug them.
Redirects feel like magic when they work and infuriating when they don't. A URL you swear you fixed keeps sending users to the old page. A campaign link mysteriously drops its UTM parameters. A form submission that used to work suddenly breaks after a "harmless" redirect got added upstream. All of that traces back to the same thing: most people know what a redirect is but have never actually seen how URL redirects work inside a browser and on the wire.
The mechanics are simpler than the folklore. A redirect is one extra request the browser makes on your behalf after a server tells it "the thing you asked for lives over there." Everything interesting about redirects, the caching, the chains, the SEO behavior, the weird POST-turns-into-GET moments, is downstream of that one flow.
This piece walks through the exact sequence of events, header by header, from the moment a user clicks a link until they land on the destination. You'll see how the browser decides to follow a redirect, why 301s stick around in caches for years, how edge platforms shortcut the round trip, and where the common bugs hide. If you've ever wondered why a redirect works some days and not others, the answer is almost always in this flow.
A URL redirect works by the server responding to a request with an HTTP 3xx status code (like 301 or 302) and a Location header pointing at a different URL. The browser reads that response, then automatically makes a new request to the URL in the Location header. The user sees only the final page, but two full HTTP round trips actually happened. The status code tells the browser whether to cache the redirect and search engines which URL to keep in their index.
Table of Contents
- The 30-Second Version
- What Actually Happens When You Click a Link
- Anatomy of a Redirect Response
- Browser Caching: Why 301s Stick and 302s Don't
- Absolute vs Relative Location Values
- What Redirects Do to POST, Cookies, and Headers
- Edge Redirects vs Origin Redirects
- What a Redirect Chain Actually Costs
- Client-Side Redirects (Meta Refresh and JavaScript)
- How to Debug a Redirect
- Redirects Inside URL Shorteners
- Frequently Asked Questions
The 30-Second Version
A URL redirect is a server response that tells the browser to make a second request at a different URL. It's not a rewrite, it's not a proxy, and it's not a client-side trick. The browser asks for URL A, the server replies with a 3xx status code and a Location header pointing at URL B, and the browser automatically issues a new request to B.
Two things ride along with that flow and cause most of the confusion downstream. First, the specific status code (301, 302, 307, 308, etc.) tells the browser whether to cache the redirect and search engines whether to swap the URL in their index. Second, the Location header can be absolute or relative, and can carry query strings or drop them depending on how it's set up. Get either of those wrong and the redirect still fires, but the outcome you expect quietly won't be the one you get.
Everything else, edge worker redirects, CDN shortcuts, chains, loops, HSTS forcing HTTP to HTTPS, is a variation on that one request-then-follow pattern.
What Actually Happens When You Click a Link
The full timeline of a single redirect, from click to final render, is more concrete than most people think. Here's what a browser does when a user clicks a link to example.com/old that redirects to example.com/new:
- DNS lookup for
example.com. The browser asks its OS resolver for the IP address ofexample.com. This may be cached from an earlier visit; if not, it's a few extra milliseconds. - TCP handshake and TLS negotiation. The browser opens a TCP connection to that IP address, then upgrades to TLS if the URL uses HTTPS. On HTTP/2 or HTTP/3, this connection is reused for later requests to the same origin.
- HTTP request for
/old. The browser sends aGET /old HTTP/1.1request with headers likeHost: example.com,User-Agent,Accept, any cookies for that origin, and so on. - Server responds with a redirect. The server's response line is something like
HTTP/1.1 301 Moved Permanently, followed by headers includingLocation: https://example.com/new. - Browser reads the Location header. It parses the URL, resolves it (relative or absolute), decides whether to follow it (it almost always does for 3xx responses), and updates the address bar to the new URL.
- Browser makes a new request to
/new. If the new URL is on the same origin and the connection is still open, it reuses the TCP/TLS connection. If it's on a different origin, it does DNS + TCP + TLS again for the new host. - Server responds to
/newwith a 200. Now the actual HTML comes back, the browser starts rendering, and the user finally sees the page.
Two full HTTP round trips happened, but the user only saw one page load. That's the entire mystery. Every "why is my redirect slow" question boils down to how many of those steps repeated on the second request, and whether any hop added an extra redirect the browser also had to follow.
One implicit but often forgotten detail: the response body of a redirect is usually empty or contains a tiny "You are being redirected" HTML snippet that browsers never render. Curl users see it. Browsers throw it away.
Anatomy of a Redirect Response
A real redirect response looks like this on the wire (formatted for readability):
HTTP/1.1 301 Moved Permanently
Server: nginx
Date: Wed, 12 Aug 2026 14:22:11 GMT
Location: https://example.com/new
Cache-Control: public, max-age=31536000
Content-Length: 0
Three headers do the actual work. The status line (HTTP/1.1 301 Moved Permanently) tells the browser this is a redirect and what kind. The Location header tells it where to go. The Cache-Control header tells it (and every proxy in between) how long to cache the redirect. Everything else is metadata.
A 3xx response without a Location header is broken. Per the HTTP spec, browsers show a blank page or an error when a redirect status arrives with nothing to follow. If you're getting mysterious blank pages after a "redirect," this is usually the culprit; something set the status code but not the header.
The specific status code matters because it changes behavior. A shortened version of the most common ones:
- 301 Moved Permanently - cache aggressively, treat destination as canonical
- 302 Found - do not cache, keep original URL in the search index
- 303 See Other - force the follow-up request to be a GET (Post/Redirect/Get pattern)
- 307 Temporary Redirect - same as 302 but strictly preserves the HTTP method
- 308 Permanent Redirect - same as 301 but strictly preserves the HTTP method
If you want the full breakdown of when each one is right, our complete guide to URL redirect types walks through all seven flavors including the client-side ones. And for the specific SEO tradeoff between the two most common codes, our 301 vs 302 explainer covers what actually matters (spoiler: less than most SEO blogs claim).
Browser Caching: Why 301s Stick and 302s Don't
Here's where behavior gets subtle. When a browser sees a 301 response, it treats that redirect as permanent and stashes it in its own cache, often for a very long time and often without an explicit expiration. The next time the user tries to visit example.com/old, the browser doesn't even bother making the request; it goes straight to example.com/new without hitting the network at all.
That local caching is why 301 is fast on repeat clicks. It's also why a 301 you committed by mistake is genuinely hard to undo. The server change alone doesn't clear the browser's cached copy. You either wait months for organic churn, or you tell affected users to clear their browsing data. Neither is great.
302s behave differently. The default HTTP semantics for a 302 say "do not cache," so the browser makes the request to the original URL every time and follows whatever the current redirect points at. Slower on repeat visits, but you can flip the destination on the server and users see the new destination immediately.
You can override both defaults with an explicit Cache-Control header. A 301 with Cache-Control: no-store won't be cached; a 302 with Cache-Control: public, max-age=3600 will be cached for an hour. This is exactly what a lot of URL shorteners do to keep dynamic links responsive: 302 the redirect but cache it for a few minutes at the edge to soak up the traffic burst without permanently locking anyone in.
The HTTP semantics for redirect caching are documented in detail in MDN's guide to HTTP redirections, which is worth bookmarking if you're going to touch redirects regularly. It has the exact rules for each 3xx code.
Absolute vs Relative Location Values
The Location header can carry either a full absolute URL (https://example.com/new) or a relative reference (/new or ../new). Both work. Both have a footgun.
Absolute URLs are unambiguous. The browser follows them exactly as written. If your Location value is https://example.com/new?utm_source=email, the browser goes to that URL with the query string intact.
Relative URLs get resolved against the requested URL. That resolution is where things go sideways. If the browser requested https://example.com/old?utm_source=email and the server responds with Location: /new, the browser navigates to https://example.com/new with no query string. The redirect quietly ate your UTM parameters. Every "why aren't my campaign links tracking" ticket that isn't a UTM builder mistake usually turns out to be this.
The fix is either to explicitly include query strings on the destination Location, or to configure your redirect layer to pass query strings through automatically. Every major framework and server has a switch for this: Nginx uses $request_uri or $args, Apache has QSA (Query String Append), Vercel has has and passQuery, Cloudflare Rules has "Preserve query string." The switch is off by default in more platforms than you'd think.
There's a related bug where a relative Location like new (no leading slash) resolves against the current directory instead of the root, which is almost never what you meant. If you're hand-rolling a redirect layer, always emit absolute URLs. It removes a whole class of ambiguity.
What Redirects Do to POST, Cookies, and Headers
Redirects don't just repeat the second request identically. The rules for what carries over are specific and, depending on the status code, sometimes surprising.
Request method. For 301 and 302, the HTTP spec is loose about whether the follow-up must use the same method as the original. Historically, some browsers converted a POST to a GET after a 301 or 302, quietly stripping the request body. Modern browsers usually preserve the method for 301, but not always. For anywhere the method actually matters (an API endpoint accepting POST or PUT), use 307 (temporary) or 308 (permanent). Those explicitly forbid the method conversion.
Cookies. Cookies get sent on the follow-up request based on the destination URL's origin, not the original one. If the redirect crosses origins (from a.com to b.com), cookies scoped to a.com don't come along; only cookies scoped to b.com do. Same-origin redirects carry cookies normally.
Custom headers. Custom headers set by JavaScript (via fetch() or XMLHttpRequest) usually get re-added by the browser on the follow-up request when the destination is same-origin. On a cross-origin redirect, they get dropped unless the destination server sends the right CORS headers to explicitly allow them.
Authorization headers. These get stripped on cross-origin redirects for security reasons. If you're calling an API that redirects to a different host, your Authorization: Bearer <token> header disappears silently. A lot of "my request works with curl -L but not from my SDK" bugs come from this.
CORS preflight. A cross-origin fetch that would normally trigger a preflight (OPTIONS) will preflight the original URL. If that URL redirects, browsers historically failed the whole request. Modern browsers handle this better, but it's still a common trip wire when your API layer redirects behind the scenes.
None of these behaviors are broken, but all of them have caught engineers off guard. The rule of thumb: keep redirects same-origin whenever you can, and never redirect API endpoints casually.
Edge Redirects vs Origin Redirects
A redirect can be emitted at any layer in your stack, and the layer changes the performance profile significantly. From slowest to fastest:
Application-level redirects. Your framework (Rails, Django, Express, Next.js, whatever) processes the request, decides it should redirect, and returns a 3xx response. This means the request had to make it all the way to your app server before anything happened. If the destination is a mile away geographically, this is the slowest option.
Web server redirects. Your reverse proxy (Nginx, Apache) handles the redirect before it ever hits your app. Faster than application-level because the app process doesn't spin up, but still requires a round trip to your origin server.
CDN edge redirects. Cloudflare Rules, AWS CloudFront Functions, Fastly VCL, Vercel vercel.json, Netlify _redirects, and similar tools evaluate the redirect at the CDN's edge node closest to the user. The request never leaves the edge; the redirect response comes back from a data center in the user's own city. This is dramatically faster for global traffic.
Edge Worker redirects. Cloudflare Workers, Vercel Edge Functions, Deno Deploy, and similar platforms let you write custom logic (auth-aware, geo-aware, feature-flagged) at the same edge layer. The speed benefit is the same; the flexibility is greater.
For high-traffic redirects (marketing links, vanity URLs, product shortcuts), pushing the redirect logic to the edge is one of the biggest wins available. A redirect that takes 40ms from the edge might take 300-400ms from origin, especially for users on other continents. Multiply that by the number of redirect hops in your funnel and the difference gets loud.
This is why URL shorteners are almost always built on edge platforms. The entire product is one request that needs to be as close to the user as physically possible.
What a Redirect Chain Actually Costs
A redirect chain is any sequence where the destination of one redirect is itself a redirect. Something like:
http://oldsite.com/page
→ 301 → http://www.oldsite.com/page
→ 301 → https://www.oldsite.com/page
→ 301 → https://newsite.com/page
→ 301 → https://newsite.com/blog/page
Each hop is a full HTTP round trip. If the user is on a slow mobile connection and the redirects hit different origins (different DNS lookups, different TLS handshakes), each hop can cost hundreds of milliseconds. Four hops of that adds up to a page that takes more than a second to even start loading, before the destination server has done any work.
Googlebot will follow chains, but Google's site-move documentation says it follows up to 10 hops before flagging a redirect error, and Google recommends keeping chains under five. It also spends more crawl budget on chained URLs, which for big sites means some pages get discovered later than they should. And every extra hop adds a chance for something to break: a DNS failure, a TLS mismatch, a rate limit trip, any of which turns a redirect into a 500 for the user.
The fix is to flatten. Every source URL should point directly at its final destination in a single hop. If you're migrating from http://oldsite.com/* to https://newsite.com/blog/*, one 301 does the whole job. Don't chain through the intermediate www and https steps; write the redirect straight to the final URL.
Auditing existing chains is the hard part on a site that's been alive for years. Screaming Frog, Sitebulb, and httpstatus.io all walk chains end-to-end and show you every hop. Running any of them over your top-linked URLs is worth a quiet afternoon.
Client-Side Redirects (Meta Refresh and JavaScript)
Not every redirect uses HTTP. Two client-side alternatives exist:
Meta refresh is an HTML tag in the document <head>:
<meta http-equiv="refresh" content="0; url=https://example.com/new">
The browser downloads the full HTML document, parses the head, sees the meta refresh, and then navigates. Delay of 0 makes it near-instant; a positive delay ("You will be redirected in 5 seconds") gives users a moment to bail.
JavaScript redirects use window.location:
<script>
window.location.replace('https://example.com/new');
</script>
replace() doesn't add a history entry; href = ... does. Small difference, big impact on the back button behavior.
Both work. Both are slower and weaker than HTTP redirects because the browser has to receive and parse the whole HTML document before anything happens. Screen readers announce the intermediate page. Search engine crawlers have to render the page to see the redirect. And on flaky connections, the redirect can fail mid-download in ways an HTTP redirect never can.
The only real use cases for client-side redirects are situations where you cannot touch the HTTP response headers (some static hosts, some CMS platforms) or the redirect needs conditional client-side logic (device detection, logged-in state routing, deep-link fallbacks that check whether an app is installed). Everywhere else, prefer HTTP.
How to Debug a Redirect
When a redirect isn't doing what you expect, the answer is almost always visible in the raw request and response. Three tools to reach for:
Browser DevTools Network tab. Paste the URL, hit enter, and check the Status column. You'll see the 3xx status on the first request and the 200 on the destination. Check "Preserve log" so cross-origin redirects don't wipe the earlier entries. Click any request to see the full headers, including the Location header and any Cache-Control directives that explain the browser's caching behavior.
curl with -I and -L. From a terminal:
# Show headers for the first response only
curl -I https://example.com/old
# Follow the full chain and show headers for every hop
curl -IL https://example.com/old
The -L flag makes curl follow redirects; the -I flag prints headers only. Combined, they give you the exact wire behavior for every hop in the chain. This is how you catch missing Location headers, unexpected chains, dropped query strings, and cache-control weirdness.
Online redirect checkers. Tools like httpstatus.io and redirect-checker.org walk chains in one click and show status codes, destinations, and response times. Useful for spotting hidden intermediate hops you didn't put there yourself (some registrars and hosts insert their own redirects when you're not looking).
For redirects inside a URL shortener, you can also usually append a + or ?debug (depending on the provider) to the short URL to see a preview page instead of the actual redirect. Our breakdown of whether URL shorteners hurt SEO covers the specific class of redirect that runs inside a shortener and how search engines actually treat it.
If none of the above show the redirect at all, it's probably a client-side redirect. Check the HTML source of the response for a <meta http-equiv="refresh"> tag or a window.location script.
Redirects Inside URL Shorteners
URL shorteners are the pure-play version of everything above. The entire product is one HTTP redirect. The user clicks u2l.ai/my-launch, the shortener returns a 3xx with a Location header pointing at the real URL, and the browser follows.
The interesting decisions are all around that one flow: which status code (301 or 302), where the redirect is emitted (edge or origin), how the response is cached, whether analytics happen inline or after the response, and whether safety checks add latency to the click. The good shorteners get all of them right without you having to think about it.
At U2L AI, redirects default to 301, which makes short links cache-friendly and clean for static use cases like printed materials and vanity URLs. You can flip individual links to 302 for dynamic use cases where the destination might change. Every redirect fires from a global edge network with 330+ locations so the round trip resolves close to wherever the click happened, which is one reason we're one of the fastest URL shorteners available. Safety checks (Google Safe Browsing, moderation, blocklists) run in parallel during link creation instead of on every click, so the redirect itself is a single lookup and a header response. If you want the full feature breakdown, the features page has the current details.
For the deeper context on how shortener redirects intersect with SEO, our piece on whether URL shorteners hurt SEO covers what Google's engineers have actually said about link equity through 301s and 302s. And if you just want to create your first branded short link, our beginner's walkthrough on shortening a URL gets you from long URL to shareable short link in under a minute.
Frequently Asked Questions
How does a URL redirect actually work?
When a browser requests a URL that's set up to redirect, the server responds with an HTTP 3xx status code and a Location header pointing at a different URL. The browser reads the Location, updates the address bar, and automatically makes a new request to that URL. The user sees only the final page, but two full HTTP round trips happened.
What is the Location header in a redirect?
The Location header is an HTTP response header that tells the browser where to go next. It's paired with a 3xx status code (like 301 or 302) and can hold either an absolute URL (https://example.com/new) or a relative reference (/new). Without a Location header, a 3xx response leaves the browser with nowhere to go and it shows a blank page.
Why do some redirects get cached and others don't?
The status code sets the default. 301 (Moved Permanently) is cached aggressively by browsers and often lasts indefinitely without an explicit expiration. 302 (Found) is not cached by default so the browser rechecks every time. Either default can be overridden with an explicit Cache-Control header on the response.
Do URL redirects slow down my website?
Each redirect adds one full HTTP round trip. A single hop is usually invisible; a chain of three or four hops can add hundreds of milliseconds to page load, especially on mobile connections. The bigger issue is redirect chains: if you can flatten them so each source URL points directly at its final destination, performance improves noticeably.
What is a redirect chain and why is it bad?
A redirect chain is when one redirect points at a URL that itself redirects, potentially through several hops before the final destination. Each hop is a full round trip, so chains slow down users, waste search engine crawl budget, and increase the chance of a failure along the way. Googlebot follows up to 10 hops before flagging a redirect error, but Google recommends keeping chains under five.
Do redirects preserve query strings and UTM parameters?
It depends on how the redirect is configured. Absolute Location URLs preserve whatever you put in them; relative Location values often strip the query string unless the server explicitly passes it through. Most redirect platforms (Nginx, Apache, Cloudflare, Vercel, Netlify) have a "preserve query string" option that's off by default.
Do redirects lose cookies or authorization headers?
Same-origin redirects preserve cookies and most headers normally. Cross-origin redirects drop cookies scoped to the original origin, and Authorization headers are stripped entirely for security reasons. This is one of the most common causes of API integrations that work with curl but fail from a browser or SDK.
What's the fastest way to emit a redirect?
Push the redirect logic as close to the user as possible. Application-level redirects are slowest (the request has to reach your app server). Web server redirects (Nginx, Apache) are faster because they skip the app. CDN or edge redirects (Cloudflare Rules, Vercel Edge Functions, Netlify) are fastest because they resolve at a data center in the user's own region without ever hitting your origin.
The Boring Superpower
Redirects are the plumbing of the web. Once you know the flow, request, 3xx status, Location header, follow, they stop being magic and start being a tool you can reason about. Most redirect problems are one of three things: a missing or wrong Location header, an accidentally cached 301, or a chain that grew hop by hop over years of quick fixes. All three are easy to spot once you know where to look.
If your redirects live inside a URL shortener, the leverage from getting them right is higher than usual because every click is a redirect. Pick a platform that handles the mechanics for you: edge-emitted responses, sane defaults (301 for static, 302 for dynamic), no chains, safety checks that don't add click latency, and analytics that don't slow the redirect down. Create a free U2L AI account and you get all of that out of the box, plus the option to bring your own custom domain and pick the exact redirect behavior you need on each link. For deeper reads on the adjacent topics, our complete guide to link tracking covers how analytics fit into the redirect flow, and our types of URL redirects breakdown walks through every 3xx code, meta refresh, and JavaScript alternative in more depth.