301-vs-302-vs-307-vs-308-redirect-guide-2026.html
< BACK TO BLOG

301 vs 302 vs 307 vs 308: the redirect code decision matrix for SEO migrations

Four HTTP redirect codes, four meaningfully different behaviours, and one consistent SEO mistake that shows up on every migration: defaulting to 302 because it is what the framework happens to emit. Here is the actual decision matrix for 301 vs 302 vs 307 vs 308, plus the real-world cost of getting it wrong.

The four codes in one sentence each

301 Moved Permanently: the canonical permanent redirect. Cacheable. Method may change from POST to GET. The default for permanent URL moves.

302 Found: temporary redirect. Cacheable but with re-validation. Method may change from POST to GET. Used by frameworks as a default; almost never the right call for SEO permanent moves.

307 Temporary Redirect: like 302 but the method is preserved. POST stays POST. Used for temporary moves where the method matters (rare in marketing-site SEO; common in APIs).

308 Permanent Redirect: like 301 but the method is preserved. POST stays POST. The HTTP/2-era replacement for 301 when method preservation matters. Modern frameworks (Next.js, Vercel) emit 308 by default for redirect() calls.

Why this matters for SEO

Google has stated publicly that 301 and 308 both transfer the full PageRank signal. 302 and 307 transfer less reliably — the assumption baked into Google's interpretation is that a temporary redirect points at a temporary destination, so the canonical signal should stay on the original URL. On a migration, this is exactly wrong: you want the canonical signal to move.

Real-world impact: a site that ships migration redirects as 302 instead of 301 typically loses 20-40% of organic traffic in the first 60 days post-cutover. The fix is not subtle, but it is also not always caught because the 302s work for users (the browser follows them, the page loads). Search Console flags the issue in the Coverage report under "Page with redirect" but most teams ignore that report during the post-cutover panic.

The decision matrix

Three questions. Answer them in order; the result determines the code.

Question 1: Is the move permanent?

If yes (URL is moving forever, the old URL will not return): use 301 or 308. If no (URL will return, this is temporary): use 302 or 307.

Question 2: Is the URL being hit by POST requests?

If yes (form submissions, API calls, JSON POSTs): use 307 or 308 (method preserved). If no (browser navigation, link click): 302 or 301 are fine.

Question 3: What does the framework default to?

Modern stacks: Next.js redirect() emits 308 by default, vercel.json [[redirects]] use 308 unless permanent: false is set, Netlify _redirects use 301 unless explicitly told otherwise. Apache mod_rewrite uses 302 by default which catches everyone the first time. Always check your framework's default before relying on it.

The four most common mistakes

  • Defaulting to 302 because Apache/Express/Flask emit it as the default for the redirect() helper. Fix: explicitly set 301 in every redirect rule on a permanent move.
  • Using 307 thinking it is the modern 301. It is not — 307 is the modern 302 (temporary, method-preserving). For permanent moves use 308 or 301.
  • Mixing 301 and 302 across the same redirect map. Pick one (301 for migrations) and use it everywhere; mixed codes confuse Search Console's reporting.
  • Forgetting that 308 preserves the POST method. If your old URL was a form submission endpoint and you 308 it to the new URL, the POST data flows through. If you 301 it, the browser converts POST to GET and the form submission is lost. Knowing the difference catches a real bug class.

When to use which, in practice

Migration redirects (old domain → new domain, old slug → new slug): use 301. The simplest, most widely supported, and explicitly stated by Google as a full PageRank transfer.

Permanent moves where method preservation matters (POST endpoints, form submissions): use 308. The PageRank transfer is identical to 301; the only difference is that POST stays POST.

Temporary moves (A/B testing, geographic redirects, maintenance): use 302. Lower-PageRank-transfer is the right behaviour because the source URL should retain its ranking signal.

Temporary moves with method preservation (API endpoints under temporary failover): use 307.

How to set each code on common platforms

Vercel (vercel.json)

[[redirects]] block. Set permanent: true for 308 (default), permanent: false for 307. To force 301 use statusCode: 301 explicitly. Most modern Vercel deploys default to 308 which is fine for migrations; the SEO-conservative pick is 301 for maximum compatibility with older crawlers and indexers.

Netlify (netlify.toml or _redirects)

_redirects syntax: /old-url /new-url 301 for permanent, /old-url /new-url 302 for temporary. Add ! to force the status: /old-url /new-url 301!.

Apache (.htaccess)

Redirect 301 /old-url /new-url for permanent. RewriteRule with [R=301,L] flag for rewrite-style redirects.

Nginx

return 301 https://example.com/new-url; inside a location block. For pattern matching: rewrite ^/old/(.*)$ /new/$1 permanent; (the permanent flag emits 301; the redirect flag emits 302).

Verifying the codes in production

Three commands every engineer should keep in muscle memory. curl -I https://example.com/old-url returns the status code in the response headers. curl -ILk follows redirects and logs every status code along the way (catches chains).

For bulk verification across hundreds of URLs, scriptable: a Node.js fetch loop that reads a CSV of old URLs and logs status + final destination. Or use the DataForSEO on-page Instant Pages endpoint, which returns the full redirect trace.

The summary

301 for permanent moves (default for SEO migrations). 308 when method preservation matters and the move is permanent. 302 for temporary moves. 307 for temporary moves with method preservation. The framework defaults are not always right; check them at deploy time.

Adjacent reading: 410 vs 404 covers the retirement case (URLs going away forever, not being moved). Same migration usually needs both decisions.

< BACK TO BLOG