Choosing 308 vs 301 for Method-Preserving Redirects

Problem Statement

You are redirecting an endpoint that receives POST requests — a form action, webhook, or API path — and need to know whether a 301 or a 308 is correct. A 301 permits clients to convert the follow-up request to GET, silently dropping the POST body, whereas a 308 guarantees the method and body are preserved. This page sits under 301 vs 302 Decision Trees.

301 versus 308 method handling A POST request following a 301 may downgrade to GET and lose its body, while a 308 preserves the POST method and body. POST Following 301 vs 308 POST /submit 301 308 may become GET request body dropped stays POST method + body preserved
A 301 lets clients downgrade POST to GET and lose the body; 308 preserves both.

When to Use This Approach

  • The redirected path accepts POST, PUT, PATCH, or DELETE — not just GET page views.
  • You are migrating a form action URL, webhook receiver, or API endpoint.
  • A client reports that data “disappears” after a redirect — a classic 301 method downgrade.
  • You want a permanent redirect that is byte-for-byte safe for request bodies.
  • You are choosing the permanent flag in a framework that emits 308 (Next.js, Nuxt).

Step-by-Step Instructions

1. Decide Method Preservation First

Ask whether the endpoint ever receives a non-GET method. If it only serves page views, 301 is fine and is the most widely cached. If it can receive POST/PUT/PATCH/DELETE, choose 308 so the method and body survive the redirect.

GET-only page move      -> 301 (permanent, method may downgrade — irrelevant for GET)
POST/API/webhook move   -> 308 (permanent, method + body preserved)

2. Configure 308 in Nginx

Nginx return accepts any status code, so emit 308 explicitly. Append $is_args$args to carry the query string, and keep the rule in the matching location.

# Permanent, method-preserving redirect for a moved form/API endpoint
location = /submit {
    return 308 /api/v2/submit$is_args$args;
}

3. Configure 308 in Apache

Apache RewriteRule takes a numeric status with R=308. Use it where the moved path may receive POST.

# 308 keeps the POST body intact across the move
RewriteEngine On
RewriteRule ^/submit$ /api/v2/submit [R=308,L,QSA]

4. Map Framework “permanent” Flags Correctly

Modern frameworks emit 308 for permanent redirects. If a tool’s permanent: true produces 308 (Next.js, Nuxt routeRules can target either), confirm it matches your method requirement; for stack-specific syntax see CMS & Framework Routing Changes.

// next.config.js — permanent: true emits 308, which is what an API move wants
{ source: '/submit', destination: '/api/v2/submit', permanent: true }

Worked Example

A webhook receiver moves from /submit to /api/v2/submit. With a 301, some clients re-issue the follow-up as GET and the JSON body is lost:

$ curl -sIL -X POST https://www.example.com/submit
HTTP/2 301
location: https://www.example.com/api/v2/submit
# client re-sends as GET -> body dropped, 400 at target

Switching the rule to 308 preserves the POST and its body:

$ curl -sIL -X POST https://www.example.com/submit
HTTP/2 308
location: https://www.example.com/api/v2/submit
HTTP/2 200

The receiver now gets the original POST body at the new path in a single hop.

Verification

  • Confirm the status code is 308, not 301: curl -sI -X POST https://www.example.com/submit | grep -i '^HTTP'.
  • Send a real POST body with curl -X POST -d '{"k":"v"}' and confirm the target processes it (200/201), proving the body survived.
  • Check the query string is preserved on the Location header for parameterised endpoints.

FAQ

What is the difference between 301 and 308? Both are permanent. A 301 historically allows clients to change the follow-up request method to GET, which drops a POST body; a 308 forbids that, preserving the method and body. For GET-only page moves they behave the same for SEO.

Do search engines treat 308 like 301? Yes. Google treats 308 as a permanent redirect equivalent to 301 for ranking and consolidation. Use 308 specifically when method and body preservation matters; use 301 for ordinary GET page moves where it has the widest caching support.

Related

← Back to 301 vs 302 Decision Trees