307 Redirect: Temporary Redirect with Method Preservation
What HTTP 307 is, how it fundamentally differs from 302 and 308, when it's essential for forms and APIs, and how to configure it on your server.
307 Temporary Redirect is an HTTP status for temporary 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 302, the browser does not downgrade the method to GET. Search engines treat 307 as a temporary redirect: link equity is not transferred and the original URL remains indexed.
What is a 307 redirect
307 Temporary Redirect is an HTTP status code introduced in HTTP/1.1 (RFC 2616) and refined in RFC 9110. It tells the client: 'The requested resource is temporarily available at a different URL. Repeat the request there using the same method and body.' The key word is 'same method': if a user submitted a POST form, a 307 requires the browser to send another POST to the new URL rather than silently switching to GET.
This is exactly what distinguishes 307 from 302. While the HTTP specification formally required 302 to preserve the method, historically most browsers changed POST to GET upon receiving a 302. The RFC authors documented this 'bug' as the de-facto behavior for 302, and 307 was introduced as the code with a guaranteed method preservation guarantee.
307 vs 302 vs 308 vs 301: 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 307
- HTTPS upgrade for POST requests: when a site accepts forms over HTTP and needs to redirect them to HTTPS without losing the request body.
- API redirects during temporary endpoint migration: when a client sends PUT/PATCH/DELETE and you need to temporarily route traffic to another host or API version.
- Load balancing and failover: when a node goes down, route requests to a standby server preserving the original method.
- Geolocation redirects: temporarily route users to a regional version while preserving POST method for form submissions.
- A/B testing for forms: temporarily route a portion of POST traffic to a test variant without changing the method.
- Maintenance windows: preserve POST requests while the primary URL undergoes maintenance.
307 redirect and SEO
From a search engine perspective, 307 is a temporary redirect. Google and Bing do not transfer link equity (PageRank) through 307: the original URL stays indexed, the destination does not gain additional authority. If a 307 remains in place long enough (several months), Google may reassess it as permanent — similar to how it treats a long-standing 302.
In practice, 307 appears in SEO audits in two contexts: HTTPS redirects (correct for POST, but 301 is preferred for regular GET pages) and redirect chains. Every extra hop in a chain — whether 307, 302, or 301 — adds latency and can hurt LCP. Keep chains to no more than two hops.
How to configure a 307 redirect
Examples for common server environments:
# Nginx: temporary redirect with method preservation
server {
listen 80;
server_name example.com;
# All HTTP traffic → HTTPS (307 preserves POST body)
return 307 https://example.com$request_uri;
}
# Specific path
location /api/v1/ {
return 307 https://example.com/api/v2/;
}# Apache (.htaccess)
# Temporary redirect for a single URL
Redirect 307 /old-endpoint https://example.com/new-endpoint
# or via mod_rewrite
RewriteEngine On
RewriteRule ^api/v1/(.*)$ https://example.com/api/v2/$1 [R=307,L]// Next.js (next.config.js) — temporary redirect
module.exports = {
async redirects() {
return [
{
source: '/api/v1/:path*',
destination: '/api/v2/:path*',
permanent: false, // permanent: false → 307
},
];
},
};<?php
// PHP: explicit 307
http_response_code(307);
header('Location: https://example.com/new-endpoint');
exit();
?># Verify via curl — confirm the response is exactly 307
curl -I -X POST https://example.com/old-endpoint
# HTTP/2 307
# location: https://example.com/new-endpointCommon questions
Discuss your project?
Share your goals and website context — I will suggest a practical next step.