301, 302, 303, 307 and 308 redirects compared
Use 301 or 308 for permanent moves and 302 or 307 for temporary ones. 307 and 308 guarantee the client repeats the same method and body; with 301 and 302, browsers turn a POST into a GET. 303 always means "now GET this other URL".
The resource has a new permanent URL, given in the Location header.
Used for domain moves, HTTP-to-HTTPS redirects and changed URL structures; search engines transfer ranking signals to the new URL. Browsers cache 301s aggressively, often with no expiry, so a mistaken 301 can stick in users' browsers long after you fix the server. For historical reasons clients may turn a POST into a GET when following it; use 308 if the method must be kept.
The resource is temporarily at a different URL, given in the Location header; keep using the original URL.
Called "Moved Temporarily" in HTTP/1.0. The classic use is redirecting to a login page or after a form post, though 303 states that intent more precisely. Browsers change a POST to a GET when following a 302 even though early specs said not to; use 307 if you need the method and body preserved.
Go fetch the result from another URL with GET.
The standard way to implement Post/Redirect/Get: after a form POST succeeds, the server answers 303 pointing at a results page, and the browser loads it with GET, so a reload does not resubmit the form. Unlike 302, the switch to GET is required, not just tolerated. It does not mean the original resource moved.
The resource is temporarily at another URL; repeat the same request, same method and body, there.
It is a 302 with the method guaranteed: a POST stays a POST. Browsers also show an internal 307 when HSTS forces an http:// URL to https://; that redirect never left the browser, so you will not find it in server logs. Use it for temporary moves of API endpoints that accept non-GET methods.
The resource has a new permanent URL; repeat the same request, same method and body, there.
It is a 301 with the method guaranteed. First defined in RFC 7538 and now part of RFC 9110. Use it when permanently moving an endpoint that receives POST, PUT or DELETE. Very old clients that predate 308 may not follow it.
Explained
Two questions decide the code. Is the move permanent? Then clients and search engines should update their links: 301 or 308. Is it temporary? Then they should keep using the original URL: 302, 303 or 307.
Must the method be kept? Early browsers changed POST to GET when following 301 and 302, and the spec eventually allowed it. 307 (temporary) and 308 (permanent) were added so a redirected POST, PUT or DELETE is replayed exactly, body included. 303 goes the other way and always switches to GET, which is what you want after a form submission (the Post/Redirect/Get pattern).
In summary: 301 permanent, method may change to GET; 302 temporary, method may change to GET; 303 temporary, always GET; 307 temporary, method kept; 308 permanent, method kept.
Gotchas
- Browsers cache 301 and 308 indefinitely unless told otherwise, so test with 302 or 307 first and switch once the rule is right.
- A 307 you see in browser dev tools on an
http://URL may be the browser's own HSTS upgrade; the server never sent it. - Redirect chains (A to B to C) slow page loads and dilute SEO signals; point each old URL straight at its final destination.
- Clients like curl do not follow redirects by default (
curl -Ldoes), and many drop theAuthorizationheader when the redirect goes to another host.
Related explainers
- 304 Not Modified304 tells the client its cached copy is still good. How ETag and If-None-Match produce it, why it is not...
- 404 Not FoundA 404 means the server has nothing at that URL. Why routes you just deployed return 404, when to use 410...
- 405 Method Not Allowed405 means the URL exists but rejects that HTTP method. Common causes: missing routes, trailing-slash...