301 vs 302 vs 307 vs 308: choosing the right redirect.

Four status codes, two questions: is the move permanent, and may the client change the method? Get the first wrong and browsers cache the wrong thing forever; get the second wrong and a POST quietly turns into a GET.

Published 2026-09-15 · 5 min read · Kirk Diamond

The grid

Method may change to GETMethod must be preserved
Permanent301 Moved Permanently308 Permanent Redirect
Temporary302 Found307 Temporary Redirect

That is the whole thing. 307 and 308 exist because 301 and 302 were specified as method-preserving but every browser ever built turned a POST into a GET when following them, so the RFCs gave up and blessed the behaviour, then added two new codes that mean what the old ones were supposed to mean.

Permanent or temporary?

Permanent (301, 308) tells clients the old URL is dead: update your bookmarks, your links, your index. Browsers cache a permanent redirect aggressively (Chrome effectively forever unless Cache-Control says otherwise), so the next visit skips the request to the old URL entirely. Search engines transfer the old URL's ranking signals to the new one and drop the old one from results over time.

Temporary (302, 307) says the resource is elsewhere for now, keep using the original URL. Browsers do not cache it by default. Search engines keep the old URL indexed and, if the redirect persists for long enough, eventually start treating it as permanent anyway.

The trap with permanent redirects is that they are permanent in the client too. If you 301 /pricing to /plans and later change your mind, visitors whose browser cached the 301 will keep landing on /plans with no request ever reaching your server for you to fix it. Add Cache-Control: max-age=... to a 301 if you want a way back, or use a 302 until you are sure.

Does the method matter?

For a GET request, no: all four behave the same. It matters when the redirected request is a POST, PUT, PATCH or DELETE.

This is why API endpoints should never redirect with 301 or 302, and why HTTP to HTTPS redirects on anything that accepts POST should be 308 (or 307). It is also why the 302-after-POST pattern (submit a form, get redirected to a confirmation page) works: it deliberately turns the POST into a GET so that refreshing does not resubmit.

Which one to use

SituationCodeWhy
HTTP to HTTPS, whole site301Permanent; every client should learn the HTTPS URL. Use 308 if the site accepts POSTs over HTTP (it should not, but legacy). Add HSTS on the HTTPS response so browsers stop asking.
www to non-www (or the reverse)301Canonical host, permanent. Search engines consolidate on the target.
Old URL structure to new after a rebuild301Transfers ranking, updates bookmarks. Keep the redirects in place for years; inbound links do not update themselves.
Trailing slash normalisation301Pick one form and redirect the other. Permanent.
After a successful form POST302 or 303Send the browser to a GET page. 303 See Other is the precise code for this; 302 is what everyone uses and behaves identically here.
Maintenance page, A/B test, geo redirect302 or 307Temporary. The original URL stays canonical. 307 if the request might be a POST.
API endpoint moved308Permanent and method-preserving. Clients that ignore 308 (rare now) get a clear failure rather than a silent GET.
Login required, send to sign-in302Temporary by nature; the user will come back.

Chains and loops

Each redirect is a full round trip: DNS, connect, TLS, request, response. http://example.com/page to https://example.com/page to https://www.example.com/page to https://www.example.com/page/ is three redirects before any content, easily half a second on a mobile connection. Collapse chains so every old URL goes to the final destination in one hop. Search engines follow up to about five hops and then give up, and each hop leaks a little of the signal you were trying to transfer.

The redirect checker shows every hop with its status, Location header and timing, which makes chains and the 302-that-should-be-a-301 obvious. It also shows a 3xx with no Location header, which is a misconfiguration that browsers render as a blank page.

Details that bite

All guides · All tools