308 Redirect: Permanent Redirect with Method Preservation
What HTTP 308 is, how it differs from 301 and 307, when it's essential for APIs and forms, and how to configure it on your server.
308 Permanent Redirect is an HTTP status for permanent redirection that requires the client to repeat the request to the new URL using the same method (POST, PUT, PATCH, etc.) and request body. Unlike 301, the browser does not downgrade the method to GET. Search engines treat 308 as a permanent redirect: link equity is transferred to the new URL and the original URL is removed from the index.
What is a 308 redirect
308 Permanent Redirect is an HTTP status code standardized in RFC 7538 (2015). It tells the client: 'The requested resource has permanently moved to a new URL. Repeat the request there using the same method and body.' The key word is 'permanently': unlike 307, which is temporary, 308 is permanent and signals to search engines that they should update the index and transfer link equity.
The 308 code closes a gap in the HTTP specification: before it existed, developers faced a dilemma — 301 is permanent but browsers de-facto change POST to GET; 307 preserves the method but only for temporary moves. 308 combines the permanence of 301 with the method-preservation guarantee of 307.
308 vs 301 vs 307 vs 302: key differences
The four redirect codes differ along two axes: permanence and HTTP method preservation.
- 301 Moved Permanently — permanent redirect, transfers link equity. Method should technically be preserved, but browsers downgrade POST→GET (behavior inherited from HTTP/1.0).
- 302 Found (Temporary) — temporary redirect, no link equity transfer. Method is de-facto changed POST→GET in most browsers.
- 307 Temporary Redirect — temporary redirect, no link equity transfer. Method is strictly preserved (POST stays POST).
- 308 Permanent Redirect — permanent redirect, transfers link equity. Method is strictly preserved. The API/form-friendly equivalent of 301.
When to use 308
- Permanent API endpoint migration: when clients send PUT/PATCH/DELETE and you need to permanently move the endpoint to a new address without losing the request body.
- Permanent form URL changes: when permanently changing the address of a registration or checkout form — preserving POST data.
- API version upgrades: migrating from /api/v1/ to /api/v2/ when permanently retiring the old version, preserving the request method.
- HTTPS upgrade for POST endpoints: when permanently moving forms and APIs from HTTP to HTTPS where preserving the method and request body is critical.
- Application route restructuring: when permanently moving form handlers to a new structure within the application.
308 redirect and SEO
From a search engine perspective, 308 is a permanent redirect equivalent to 301. Google and Bing transfer link equity (PageRank) through 308: the original URL is removed from the index and the destination receives the original URL's authority. Search engine crawler behavior for 308 is identical to 301 — Googlebot follows the redirect and updates the index accordingly.
In practice, the SEO difference between 301 and 308 is negligible — both transfer equity and both are permanent. The choice matters only in the context of APIs and forms: if the application uses POST/PUT/PATCH requests and the method is critical, 308 is preferable. For regular HTML pages with GET requests, use the familiar 301.
How to configure a 308 redirect
Examples for common server environments:
# Nginx: permanent redirect with method preservation
server {
listen 80;
server_name example.com;
# All HTTP traffic → HTTPS (308 preserves POST body and is permanent)
return 308 https://example.com$request_uri;
}
# Permanent API endpoint migration
location /api/v1/ {
return 308 https://example.com/api/v2/;
}# Apache (.htaccess)
# Permanent redirect for a single URL with method preservation
Redirect 308 /old-endpoint https://example.com/new-endpoint
# or via mod_rewrite
RewriteEngine On
RewriteRule ^api/v1/(.*)$ https://example.com/api/v2/$1 [R=308,L]// Next.js — permanent redirect with exact 308 status
// Note: permanent: true uses 301 — use middleware for exact 308:
import { NextResponse } from 'next/server';
export function middleware(request) {
if (request.nextUrl.pathname.startsWith('/api/v1/')) {
const newUrl = request.nextUrl.clone();
newUrl.pathname = newUrl.pathname.replace('/api/v1/', '/api/v2/');
return NextResponse.redirect(newUrl, { status: 308 });
}
}<?php
// PHP: explicit 308
http_response_code(308);
header('Location: https://example.com/new-endpoint');
exit();
?># Verify via curl — confirm the response is exactly 308
curl -I -X POST https://example.com/old-endpoint
# HTTP/2 308
# location: https://example.com/new-endpointCommon questions
Discuss your project?
Share your goals and website context — I will suggest a practical next step.