What each status code tells a browser and a crawler
There are more than two redirects, and most teams only use two of them. The distinction that matters at the protocol level isn't permanent-versus-temporary — it's whether the request method survives the hop.
A 302 historically allowed clients to convert a POST into a GET. That's why 307 and 308 exist: they say the same thing about permanence, and they promise not to change the method.
| Code | Means | Method preserved? | Use it for |
|---|---|---|---|
| 301 Moved Permanently | This URL is gone for good; use the new one | Not guaranteed | Migrations, HTTPS, www consolidation, retired URLs |
| 302 Found | Temporarily elsewhere; keep asking for this URL | Not guaranteed | Campaigns, A/B tests, short-lived diversions |
| 307 Temporary Redirect | Same as 302, method and body preserved | Yes | Temporary redirects on POST endpoints and APIs |
| 308 Permanent Redirect | Same as 301, method and body preserved | Yes | Permanent redirects where method matters |
| 303 See Other | Go fetch this other thing with GET | No, forced to GET | Post-form-submission redirects |
| 503 Service Unavailable | Site is down, come back later | n/a | Planned maintenance — with a Retry-After header |
Why Google says the SEO difference is small
Google's own line on this has been consistent for years: both 301 and 302 pass signals, and Google uses the code as an input to canonicalisation rather than as a binding instruction. A permanent redirect is a strong signal that the target should be the canonical URL. A temporary redirect is a weaker one.
Google also watches what you actually do. Leave a 302 in place for six months and it gets treated as permanent, because it plainly is. Ship a 301 and reverse it two weeks later and Google treats the original as still live, because it plainly is.
So the fear that a 302 'loses link juice' is largely pre-2016 folklore. If your only concern is Google, the two codes are close to interchangeable, and the canonical tag on the destination is doing more work than either — canonical vs noindex covers where that fits. That's the reassuring half of the answer. Here's the half that costs money.
The real damage path: a 301 you cannot take back
A 301 is a permanent redirect, and browsers take that literally. In the absence of explicit caching headers, a browser is entitled to cache a permanent redirect and stop asking the origin server about that URL. Historically, browsers cached them for as long as they felt like — effectively forever from a user's point of view.
Think about what that means operationally. You ship a bad rule at 4pm on Friday: /products/* now 301s to /shop/. You catch it at 6pm and revert the server. The server is fine. Every visitor who touched a product page in those two hours still has a permanent redirect sitting in their browser cache, and their browser will not ask you again. You cannot purge it. You have no access to it. They see the wrong page until they clear their cache, which they will not do.
It gets worse if the fix is naive. The instinct is to redirect the wrong destination back to the original — /shop/ 301s to /products/. For every affected browser that's now an infinite loop, and they see an error page instead of your store. The same problem exists one layer up at the CDN, except edge caches can be purged. That's why edge mistakes are recoverable and browser mistakes are not.
If you've already shipped a bad 301
You have three options, and none of them are good. Make the destination serve the correct content, so cached users land somewhere useful. Or move the correct content to a genuinely new URL that no browser has a cached rule for, and link to that. Or wait, and accept the loss.
Do not build the reverse redirect. That's the loop, and it converts a subset of confused users into a subset of users who cannot reach your site at all.
Which code for maintenance, tests and campaigns
Most wrong redirects come from treating 301 as the default for everything because someone read that it's better for SEO. Here's the decision, case by case.
| Situation | Right answer | Why |
|---|---|---|
| Site migration, URL restructure, HTTP to HTTPS | 301 (or 308) | The old URL is genuinely never coming back. |
| Planned maintenance or a deploy window | 503 + `Retry-After` | A redirect tells Google the page moved. It didn't. It's just down. |
| A/B test sending some users to a variant | 302 | Temporary by definition. Google's own testing guidance says so. |
| Vanity or campaign URL that will be reused | 302 or 307 | Next quarter it points somewhere else. Don't burn it permanently. |
| Out-of-stock product coming back | Leave it at 200 | 301ing to a category kills a page that has links and rankings. |
| Product discontinued forever | 301 to the closest equivalent | Not to the homepage — Google often treats that as a soft 404. |
| Geo or language routing by IP | Neither — don't auto-redirect | Googlebot crawls mostly from one region. IP redirects can hide the rest of your site from it. |
| Retired page with no equivalent | 410 Gone | Honest, and it leaves the index faster than a 404. |
Redirect chains, hops, and the migration that goes sideways
The most common technical failure in a replatform isn't the wrong code. It's the accumulation of hops. Old URL 301s to the 2021 structure, which 301s to the HTTPS version, which 301s to the trailing-slash version, which 301s to the new CMS path. Four hops, four chances to break, and a slow first byte for everyone clicking an old link.
Google documents following roughly ten redirect hops per crawl attempt before it reports an error. Browsers typically stop near twenty. Neither number is a budget — ship one hop. The discipline that gets you there is unglamorous, and it's most of what site migration work actually is.
- Crawl the old site before you touch anything. Every indexed URL, every URL with a backlink, every URL with organic clicks in the last twelve months. That list is your redirect map, and there is no way to reconstruct it afterwards.
- Map to the closest equivalent page, one to one. Bulk-redirecting a category to the homepage is the fastest way to lose the traffic you're trying to protect.
- Flatten the chains. Every old URL should point directly at the final destination, not at an intermediate that redirects again. Re-crawl and fix until every source resolves in one hop.
- Update internal links to the new URLs. Links pointing at redirects work, and they also broadcast that your own site doesn't know where its pages are.
- Keep the redirects for at least a year, longer if the old URLs have real backlinks. There's no cost to leaving them in place and a real cost to removing them.
- Watch Search Console's page indexing report weekly for two months for redirect errors and 'Page with redirect' appearing where it shouldn't.
Your framework already picked for you
Most redirect bugs aren't decisions. They're defaults nobody read. Worth knowing what your stack does when you don't specify a code.
- Apache mod_alias —
Redirect /old /newissues a 302 unless you say otherwise. UseRedirect 301orRedirectPermanent. - nginx —
rewrite ... redirectis a 302;rewrite ... permanentis a 301.return 301is explicit and clearer. - Express —
res.redirect(url)defaults to 302. Pass the status:res.redirect(301, url). - Next.js — in
next.config.js,permanent: trueemits a 308 andpermanent: falseemits a 307. Both preserve the method, both are correct, and 308 is the permanent one. - WordPress redirect plugins — usually default to 301, which is why so many WordPress sites carry permanent redirects somebody meant to be temporary.
How to check what you actually shipped
One command settles every argument in this article: curl -sIL https://yoursite.com/old-page, then read the chain of status codes. More than one 3xx before the 200 means you have a chain. A 301 where you meant a 302 means fix it now, while the cache population is still small.
Run it from a machine that has never visited the site. Your own browser is the least reliable witness you have, for exactly the reason this article is about.