301 vs 302 Redirects
A redirect tells a client that the URL it asked for lives somewhere else, and whether that move should be treated as lasting. Get the status code wrong and browsers (and search engines) may keep the old URL, or they may forget a POST body, or they may chain five hops until something times out. This guide covers 301 versus 302, plus 307 and 308, domain moves, www versus non-www, paths and query strings, redirect chains, and examples in Apache .htaccess. Nginx and application-level redirects follow the same status-code ideas even if the syntax differs.
What the codes mean
| Code | Usual meaning | Method handling (practical) |
|---|---|---|
| 301 | Permanently moved | Clients should use the new URL next time; method may change to GET |
| 302 | Found (temporary) | Do not assume the old URL is gone; method may change to GET |
| 307 | Temporary redirect | Keep the method (POST stays POST) |
| 308 | Permanent redirect | Keep the method; treat the new URL as lasting |
For ordinary page-to-page moves on a brochure or content site, 301 is the default: the old path is done. Use 302 (or 307 if you care about keeping POST) when the old URL should work again later: A/B tests, a short maintenance jump, a seasonal path. Search engines may still treat long-lived 302s as de facto permanent, so do not leave a “temporary” move for years if you mean 301.
Forms that POST should not 301/302 onto a GET if you need the body. That is what 307/308 are for. Many site owners never need them; shops and APIs do.
When to use which
- Old blog slug → new slug: 301, one hop, to the final HTTPS URL.
- HTTP → HTTPS: 301 (once TLS works). See HTTPS and SSL certificates.
- You will restore the old URL next week: 302 or 307.
- Domain name change you intend to keep: 301 from every old URL to the matching new URL.
- Geolocation or device “we might send you elsewhere”: be careful; a cached 301 can stick a user to the wrong place. Prefer 302 if it must vary, or do not redirect at all.
Do not 301 a URL to a page that is only a poor substitute (every deleted product to the home page) if you can send it to the real replacement or a category. Soft 404s dressed as 200s are a different mistake; redirects should point at something equivalent when you have it.
Domain moves
Moving example.com to example.net (documentation names):
- New site live on the new domain, with HTTPS working.
- On the old domain, 301 each path to the same path on the new domain, not everything to the new homepage.
- Keep the old domain’s DNS and hosting long enough for links and bookmarks. How long depends on how important those links are; months is common, not minutes.
- Update internal links on the new site so they do not bounce through the old domain.
Match scheme and host. Redirect to https://www.example.net/page if that is canonical, not to an HTTP URL that will redirect again. DNS still has to resolve both names; redirects are HTTP, after DNS. If you are changing IPs as well, read DNS records explained so mail MX records are not swept into the move.
www versus non-www
Pick one canonical host and stick to it. Both www.example.com and example.com should resolve, then one should 301 to the other. Mixing them splits cookies and confuses canonical tags (see meta tags, favicons and social previews).
# Apache: apex to www, HTTPS assumed already or combined carefully
RewriteEngine On
RewriteCond %{HTTP_HOST} ^example\.com$ [NC]
RewriteRule ^ https://www.example.com%{REQUEST_URI} [R=301,L]
Test both: with and without a path, with a query string, with POST if you have forms on the apex. Certificates must include both names or the first hop will warn before the redirect runs.
Keeping paths and query strings
A useful redirect preserves the path unless you intentionally map it. %{REQUEST_URI} in Apache includes the path and the query string in many setups; know whether your rule strips ? parameters. Marketing links with UTM tags should still land on the same page with the same query unless you have a reason to drop them.
# Map one old file to a new path, keep query string
RewriteRule ^old-page\.html$ /new-page/ [R=301,L,QSA]
QSA appends the original query string. Without it, you may drop ?ref=flyer. For a one-to-one domain move, prefer a generic “same path on new host” rule rather than hundreds of hand lines, then add exceptions for URLs that changed shape.
Trailing slashes are a common loop: /page → /page/ → /page. Pick a convention and implement it once, at one layer (CDN, server, or app), not at all three.
Redirect chains and loops
A chain is extra hops: http://example.com/page → http://www.example.com/page → https://www.example.com/page → https://www.example.com/page/. Each hop costs time and can lose method or headers. Collapse to one 301 to the final URL.
A loop never finishes. Browsers stop with an error. Causes: two hosts each redirecting to the other; HTTPS redirect plus an app that forces HTTP; www rules that fire twice; IPv6 vs IPv4 vhosts with different configs. Test with a tool that shows status codes for each hop, or with:
# Conceptually: first response should already be the final URL
# curl -I http://example.com/old-page
# Look for one Location: https://www.example.com/new-page/
Remove the intermediate hosts from public links as you find them. Chains in old PDF flyers you cannot reprint are why the first hop should still land correctly.
.htaccess examples (Apache)
Only if the site actually uses Apache with AllowOverride for rewrite. Syntax errors in .htaccess can 500 the whole site. Back up the file, change, request one URL, revert if needed.
RewriteEngine On
# HTTP to HTTPS (same host), then handle host in a separate, non-chaining way if possible
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
# Single page
Redirect 301 /old-page https://www.example.com/new-page/
# Temporary
Redirect 302 /promo https://www.example.com/promo-2026/
Redirect and RewriteRule can fight. Prefer one style per task. Nginx uses return 301 / return 302 in server blocks instead. Application frameworks have their own redirect helpers; they should emit the same codes.
Checklist
- 301 for lasting moves; 302/307 when the old URL should return; 307/308 when POST must survive.
- One hop to the final HTTPS canonical host and path.
- Paths mapped 1:1 on a domain change whenever the content still exists.
- Query strings preserved unless you mean to drop them.
- No trailing-slash or www loops; test with headers, not only a browser bar.
Write the canonical URL down (scheme + host + slash rule) and make every redirect point there. Everything else is a chain waiting to happen.
Related guides
General technical information; test changes carefully and keep backups of your settings.