308 Permanent Redirect: The Modern Alternative to 301

What the 308 Permanent Redirect status code is, how it differs from 301 by preserving the HTTP method, when to use it for APIs and POST-heavy applications, and browser support details.

The 308 Permanent Redirect is a status code that does the same thing as a 301, with one important difference: it guarantees the browser will use the same HTTP method for the redirected request. If the original request was a POST, the redirect will also be a POST. If it was a PUT, the redirect will be a PUT.

With a 301, browsers are allowed to change a POST request to a GET when following the redirect. Most browsers do exactly that. For regular website pages (where every request is a GET anyway), this distinction does not matter. But for APIs, form submissions, and POST-heavy applications, it matters a lot.

For a comparison of all redirect status codes, see our HTTP Redirect Guide and HTTP Redirect Status Codes.

The problem 308 was created to solve

The 301 status code has been around since HTTP/1.0 in 1996. The original specification said clients should not change the request method when following a 301 redirect. But browsers ignored this. When a browser received a 301 response to a POST request, it would change the method to GET and redirect without the request body.

This was not a bug. It was practical. If a user submitted a form and got redirected, repeating the POST to the new URL could cause duplicate submissions (duplicate orders, duplicate payments, duplicate account creations). Browsers played it safe and switched to GET.

The HTTP specification eventually acknowledged reality. RFC 7231 (2014) updated the 301 definition to say that clients "may" change the method from POST to GET. [1] The behavior that was technically wrong became officially acceptable.

But this created a gap. There was no permanent redirect code that guaranteed method preservation. The 307 Temporary Redirect already existed for temporary redirects that preserve the method, but its permanent counterpart did not exist.

RFC 7538 (2015) filled that gap with 308 Permanent Redirect. [2]

What the spec says

RFC 7538 defines the 308 status code: [2]

The 308 (Permanent Redirect) status code indicates that the target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs. The server is suggesting that a user agent with link-editing capability can permanently replace references to the effective request URI with one of the new references sent by the server.

The key addition over 301:

The server SHOULD generate a Location header field in the response containing a preferred URI reference for the new permanent URI. [...] This status code is similar to 301 (Moved Permanently), except that it does not allow changing the request method from POST to GET.

That last sentence is the entire reason 308 exists.

308 vs 301: The real difference

Here is the difference in practice. Say a client sends a POST request with a JSON body:

POST /api/v1/users HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"name": "Jane", "email": "[email protected]"}

With a 301 response:

HTTP/1.1 301 Moved Permanently
Location: https://api.example.com/api/v2/users

The browser is allowed to change this to a GET request, dropping the body:

GET /api/v2/users HTTP/1.1
Host: api.example.com

The original POST data is gone. The redirected request does something completely different from what the client intended.

With a 308 response:

HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/api/v2/users

The browser must preserve the method and body:

POST /api/v2/users HTTP/1.1
Host: api.example.com
Content-Type: application/json

{"name": "Jane", "email": "[email protected]"}

The request arrives at the new URL exactly as the client sent it. The POST stays a POST. The body stays intact.

The redirect status code family

Understanding 308 is easier when you see how it fits into the full set of redirect codes. There are two dimensions: permanence and method preservation.

                    May change method       Must preserve method
                    ─────────────────       ────────────────────
Permanent:          301 Moved Permanently   308 Permanent Redirect
Temporary:          302 Found               307 Temporary Redirect
Always GET:         303 See Other           (no equivalent)

301 and 302 are the original redirect codes. Browsers historically changed POST to GET for both of them, even though the specs originally said not to. 307 and 308 were created to give developers explicit control over method preservation, without relying on browser behavior that contradicted the spec.

For the comparison between 301 and 302, see 301 vs 302 Redirects. For 307, see 307 Temporary Redirect.

When to use 308

API version migrations

When you permanently move an API endpoint from /api/v1/ to /api/v2/, clients may be sending POST, PUT, PATCH, or DELETE requests. A 301 redirect could silently convert those to GET requests, breaking the API. A 308 preserves the method and body, so the API migration works correctly.

HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/api/v2/users

POST-heavy web applications

Some web applications route most of their traffic through POST requests. Payment processors, form-heavy business applications, and single-page apps that use POST for navigation can all benefit from 308 when a permanent URL change is needed.

Moving API endpoints to a new domain

When migrating an API from api.old-domain.com to api.new-domain.com, 308 ensures that all request methods continue to work during and after the migration. Clients that still hit the old domain get redirected to the new one without their requests being mangled.

Preserving webhooks

Webhook endpoints receive POST requests from external services. If you need to permanently change a webhook URL, a 308 redirect on the old URL ensures the incoming POST requests (and their payloads) reach the new endpoint intact.

When 301 is still the right choice

For the vast majority of websites, 301 is fine and 308 is unnecessary. Here is why:

Regular web pages only receive GET requests. When a user clicks a link or types a URL, the browser sends a GET request. The method preservation difference between 301 and 308 only matters for non-GET methods. If all your traffic is GET, 301 and 308 behave identically.

Search engines understand 301. Google, Bing, and other search engines have decades of experience with 301 redirects. They process 308 correctly too, but 301 has a longer track record and more explicit documentation from search engine vendors about how ranking signals transfer.

Universal compatibility. Every HTTP client, proxy, CDN, and browser supports 301. While 308 support is now widespread, 301 has zero compatibility concerns.

The rule of thumb: if your users visit your site in a browser by clicking links, use 301. If you are building an API or handling programmatic POST/PUT/DELETE requests, consider 308.

Browser and client support

308 is supported by all modern browsers: [3]

  • Chrome 36+ (2014)
  • Firefox 14+ (2012)
  • Safari 7+ (2013)
  • Edge 12+ (2015)
  • Opera 24+ (2014)

For practical purposes, every browser your users are running supports 308. The only clients where you might encounter issues are very old HTTP libraries, embedded systems, or custom clients that have not been updated in a decade. If your API clients are modern HTTP libraries (axios, fetch, requests, HttpClient), 308 support is built in.

Test your specific clients

If you are migrating an API to use 308, test with the actual HTTP clients your consumers use. Most modern clients handle 308 correctly, but some older libraries may not follow the redirect automatically or may fall back to GET. Run a quick test before deploying.

Implementation examples

Nginx

# Single endpoint redirect
location = /api/v1/users {
    return 308 https://api.example.com/api/v2/users;
}

# Pattern-based redirect
location /api/v1/ {
    return 308 https://api.example.com/api/v2$request_uri;
}

Apache

# Single endpoint redirect
Redirect 308 /api/v1/users https://api.example.com/api/v2/users

# Pattern-based redirect with mod_rewrite
RewriteEngine On
RewriteRule ^api/v1/(.*)$ https://api.example.com/api/v2/$1 [R=308,L]

Node.js / Express

app.all('/api/v1/*', (req, res) => {
  const newPath = req.path.replace('/api/v1/', '/api/v2/');
  res.redirect(308, `https://api.example.com${newPath}`);
});

Note the use of app.all() instead of app.get(). Since the point of 308 is to handle all HTTP methods, the route handler needs to match all methods too.

Caching behavior

Like 301, the 308 response is cacheable by default. [2] Browsers and intermediate proxies can store the redirect and skip the original server on subsequent requests.

The same caching advice that applies to 301 applies to 308: set an explicit Cache-Control header so you can control how long clients remember the redirect.

HTTP/1.1 308 Permanent Redirect
Location: https://api.example.com/api/v2/users
Cache-Control: max-age=86400

This gives you a 24-hour recovery window if you make a mistake. Without an explicit cache header, clients may cache the 308 indefinitely.

SEO implications

Google treats 308 the same as 301 for ranking signal transfer. Both are permanent redirects, and both pass full link equity to the destination URL. [4]

That said, there is no SEO advantage to using 308 over 301 for regular web pages. If you are doing a site migration, domain change, or URL restructure where all traffic is browser-based GET requests, use 301. It is more widely recognized in SEO documentation and tooling.

Use 308 when you need the method preservation guarantee. Do not use it because you think it is "better" or "newer." The best redirect code is the one that matches your use case.

Common mistakes

Using 308 for regular website pages

If your website only serves HTML pages to browsers, 308 adds no value over 301. It is not wrong, but it signals to other developers that method preservation matters for this redirect, which is misleading when every request is a GET.

Forgetting to handle the request body

When you set up a 308 redirect on your server, make sure the destination endpoint can actually receive the same request method and body. A 308 redirect from a POST endpoint to a URL that only accepts GET will result in a 405 Method Not Allowed error at the destination.

Mixing 308 and 301 in a chain

If a redirect chain includes both 308 and 301 hops, the 301 hop can still change the method to GET. The method preservation of 308 only applies to that single hop, not to subsequent redirects in the chain.

POST /old --308--> /middle --301--> /new
                                     ^
                      Method may change to GET here

If method preservation matters, every hop in the chain needs to be 308. Better yet, avoid the chain entirely and redirect directly to the final destination. See Redirect Chains Explained for more on why chains are a problem.

The bottom line

308 Permanent Redirect exists for one reason: permanent redirects that must preserve the HTTP method. If you are building or maintaining an API, handling webhook migrations, or working with POST-heavy applications, 308 is the correct tool. For standard websites where all traffic is GET requests, 301 remains the right choice. Pick the code that matches what your application actually needs.

References

  1. IETF, "RFC 9110 - HTTP Semantics, Section 15.4.2: 301 Moved Permanently," June 2022. https://httpwg.org/specs/rfc9110.html#status.301
  2. IETF, "RFC 7538 - The Hypertext Transfer Protocol Status Code 308 (Permanent Redirect)," April 2015. https://www.rfc-editor.org/rfc/rfc7538
  3. Can I Use, "HTTP 308 Permanent Redirect." https://caniuse.com/http-status-308
  4. IETF, "RFC 9110 - HTTP Semantics, Section 15.4.9: 308 Permanent Redirect," June 2022. https://httpwg.org/specs/rfc9110.html#status.308

Never miss a broken redirect

Trace redirect chains and detect issues before they affect your users and SEO. Free instant tracing.

Try Redirect Tracer