The resource has been permanently moved to a new URL, and the client must use the same HTTP method when making requests to the new location. Unlike 301, a POST request redirected with 308 remains a POST and does not change to GET.
HTTP 308 Permanent Redirect is a status code that combines the permanence of 301 Moved Permanently with the method-preservation guarantee of 307 Temporary Redirect. When a server returns 308, it tells the client that the resource has permanently moved to a new URL and that the client must use the exact same HTTP method when following the redirect. A POST stays a POST, a PUT stays a PUT, and the request body is retransmitted unchanged to the new location.
The 308 status code was introduced in RFC 7538 to fill a gap in the HTTP specification. Before 308, developers who needed a permanent redirect that preserved the HTTP method had no standard option. The existing 301 code was permanent but allowed browsers to change POST to GET, while 307 preserved the method but was only temporary. This created a real problem for API developers migrating endpoints that handle mutation requests, as 301 could silently convert a POST to a GET and break the integration.
In practice, 308 is most commonly used for API endpoint migrations and version upgrades where the URL change is permanent and the endpoints accept POST, PUT, or DELETE requests. It is less common for traditional web pages, where 301 is sufficient because most page navigations use GET. However, for single-page applications that submit forms or perform client-side API calls, 308 ensures the redirect works correctly regardless of the HTTP method being used.
A REST API endpoint has been permanently relocated to a new URL path or domain. Using 308 ensures that POST, PUT, and DELETE requests continue to use the correct HTTP method at the new location.
An old API version is permanently retired and all traffic should go to the new version. 308 preserves the HTTP method, so POST /api/v1/users becomes POST /api/v2/users without method conversion.
Multiple API domains are being consolidated into a single domain. 308 ensures that all request methods are preserved during the permanent migration.
API paths are being restructured for consistency. 308 ensures that clients sending mutation requests continue to use POST, PUT, or DELETE at the new paths.
When permanently redirecting API endpoints that handle POST, PUT, or DELETE requests, always use 308 instead of 301. This guarantees the HTTP method and request body are preserved.
After implementing 308 redirects, update your API documentation to reference the new URLs. While 308 handles existing integrations, new implementations should target the destination directly.
Since 308 is permanent, browsers and proxies will cache the redirect. Ensure the Location header is correct before deploying, as cached redirects are difficult to undo.
Track how many requests are still hitting the 308 redirect versus going directly to the new URL. Over time, redirect traffic should decrease as clients update their configurations.
// Express.js — 308 permanent redirect preserving method
const express = require('express');
const app = express();
// Permanent API versioning redirect
app.all('/api/v1/*', (req, res) => {
const newPath = req.path.replace('/api/v1/', '/api/v2/');
const newUrl = newPath + (req.url.includes('?')
? req.url.slice(req.url.indexOf('?')) : '');
// 308 preserves POST/PUT/DELETE methods permanently
res.redirect(308, newUrl);
});
// Permanent domain migration for API
app.all('/legacy-api/*', (req, res) => {
const newUrl = `https://api.example.com${req.url.replace('/legacy-api', '')}`;
res.redirect(308, newUrl);
});
# Flask — 308 permanent redirect preserving method
from flask import Flask, redirect, request
app = Flask(__name__)
# Permanent API versioning redirect
@app.route('/api/v1/<path:path>', methods=['GET','POST','PUT','DELETE','PATCH'])
def v1_redirect(path):
new_url = f'/api/v2/{path}'
if request.query_string:
new_url += f'?{request.query_string.decode()}'
return redirect(new_url, code=308)
# Permanent domain migration for API
@app.route('/legacy-api/<path:path>', methods=['GET','POST','PUT','DELETE'])
def legacy_redirect(path):
new_url = f'https://api.example.com/{path}'
return redirect(new_url, code=308)
Both indicate a permanent redirect. The difference is that 301 allows browsers to change the HTTP method from POST to GET during redirection, while 308 strictly preserves the original method. Use 308 for API endpoints that accept POST, PUT, or DELETE.
Use 308 when the redirect is permanent and you need to preserve the HTTP method. Use 307 when the redirect is temporary and method preservation is needed. The permanence is the key distinction.
Yes. All modern browsers support 308, including Chrome, Firefox, Safari, and Edge. The specification was finalized in 2015, and browser support has been universal since approximately 2016.
Yes. Search engines treat 308 as a permanent redirect and transfer ranking signals to the new URL, just like 301. However, since 308 is newer, some SEO tools may display it differently in their reports.
You can, but 301 is more conventional for regular web pages since page navigations use GET requests. Reserve 308 for situations where method preservation matters, such as API endpoints or form submission targets.
Get instant alerts when your endpoints go down. 60-second checks, free forever.
Start Monitoring Free →