devkult_
tools29converters34
home/blog/301-vs-302-vs-307-vs-308
httpseoredirects

301 vs 302 vs 307 vs 308: Which Redirect Should You Use?

HTTP has four everyday redirect codes, and choosing between them comes down to two questions:

  1. Is the move permanent? Permanent redirects tell search engines to index the new URL and let browsers cache the redirect.
  2. Must the request method be preserved? Some redirects let clients turn a POST into a GET; others forbid it.
Method may change to GET Method preserved
Permanent 301 Moved Permanently 308 Permanent Redirect
Temporary 302 Found 307 Temporary Redirect

There's also 303 See Other, which always switches to GET. It exists for one job: sending a browser to a result page after a form POST.

Why "the method may change" exists

Early browsers followed 301 and 302 by requesting the new URL with GET, even when the original request was a POST — contrary to the spec of the time. So much software came to rely on that behaviour that HTTP/1.1 accepted it, and added 307 and 308 for clients that need the method kept intact. Today:

  • A browser following a 301 or 302 after a POST sends a GET, and drops the body.
  • A browser following a 307 or 308 re-sends the POST with the same body.

For ordinary links, which are always GETs, 301 and 308 behave identically, as do 302 and 307. The difference only bites for forms and APIs.

Permanent vs temporary, for SEO

Google treats 301 and 308 as strong signals that the new URL is canonical: it indexes the target and consolidates ranking signals there. 302 and 307 keep the old URL in the index, on the assumption that the redirect is temporary. (Google has said a long-lived 302 may eventually be treated like a 301, but don't rely on it.)

Browsers cache permanent redirects aggressively — often indefinitely, unless the response says otherwise. That's great for performance and painful when you get one wrong: visitors keep following the cached redirect after you've removed it from the server. Ship new redirects as 302 first, then switch to 301 once you're sure.

Which one to use

  • Moving pages for good — a new URL structure, http → https, www normalisation: 301, or 308. Google treats them the same.
  • Moving an API endpoint permanently: 308, so POST and PUT requests keep working.
  • Temporary detours — a maintenance page, an A/B test, a regional redirect: 302, or 307 if the endpoint accepts POST.
  • After a successful form submission: 303 to the confirmation page (Post/Redirect/Get), so refreshing doesn't resubmit the form.
  • Login walls — "sign in, then come back": 302 or 303 to the login page, then back to the original URL.

What frameworks send by default

Framework Default status
Express res.redirect(url) 302
Next.js redirect() 307 (303 inside a Server Action)
Next.js permanentRedirect() and permanent: true redirects 308
Django redirect() 302 (301 with permanent=True)
Flask redirect() 302
nginx return whatever code you write

Common mistakes

  • Redirect chains. A → B → C costs a round trip per hop. Point every old URL straight at its final destination.
  • Sending everything to the homepage. Redirecting retired pages to / instead of a relevant replacement is treated as a soft 404. If there's no replacement, return 410 Gone.
  • Loops. Two rules that redirect to each other — often http/https or trailing-slash rules living in different layers — produce "too many redirects". curl -sIL prints every hop.
  • Dropping the query string. Make sure your rule carries ?utm_source=… and other parameters across.

Check what a URL actually returns

curl -sIL https://example.com/old-path | grep -iE '^(HTTP|location)'

Or paste a list of URLs into the HTTP Status Checker to see each one's status and response headers. For every other status code, see the HTTP status code reference.

More from the blog