HTTP 307 Temporary Redirect
307 is the strict version of 302: the resource is temporarily elsewhere, and the client must not change the request method when following the redirect. A POST with a JSON body is re-sent as a POST with the same body to the new URL.
307 Temporary Redirect
Temporarily redirected: repeat the same request, with the same method and body, at the Location URL.
Who fixes it: Server config. Clients follow it automatically. A 307 you didn't expect usually comes from a framework default or from the browser itself (HSTS).
What 307 means
Like 302 it's temporary: clients keep using the original URL, and caches don't store the redirect unless explicitly told to.
Next.js uses 307 a lot. redirect() from next/navigation in Server Components and Route Handlers, NextResponse.redirect(), and permanent: false redirects in next.config all send 307 by default. Inside a Server Action, redirect() sends 303.
Source: RFC 9110 §15.4.8.
Why you're seeing a 307
- Chrome DevTools shows
307 Internal Redirectforhttp://URLs on HSTS sites. That redirect never left the browser: the domain sentStrict-Transport-Securityearlier or is on the HSTS preload list, so Chrome upgrades to HTTPS by itself. The server never saw the request. - A Next.js
redirect()or middleware redirect, which defaults to 307. - Amazon S3 returns
307 Temporary Redirectwhen a request reaches the wrong regional endpoint, typically shortly after a bucket is created while DNS propagates. - A temporary redirect in a load balancer or API gateway that needs to keep
POSTbodies intact. - CORS: a preflight
OPTIONSrequest that receives a 307 fails, because browsers require a 2xx response to the preflight. Point the client at the final URL.
How to work with 307
Follow it with curl
curl -L re-sends the POST body on 307 and 308, but switches POST to GET on 301, 302 and 303, like browsers. Don't add -X POST together with -L: it forces POST on every hop.
curl -i -L https://api.example.com/v1/orders \
-H 'Content-Type: application/json' \
-d '{"sku":"A-1","qty":2}'
HTTP/2 307
location: https://eu.api.example.com/v1/orders
HTTP/2 201Choose the code in Next.js
Use permanentRedirect() (308) for moves that are permanent. In middleware (proxy.ts in Next.js 16), pass a status as the second argument to NextResponse.redirect().
import { redirect, permanentRedirect } from 'next/navigation';
redirect('/login'); // 307 (303 inside a Server Action)
permanentRedirect('/new-url'); // 308
// middleware / proxy
return NextResponse.redirect(new URL('/new-url', request.url), 308);Express
Pass the status explicitly; the default is 302.
app.post('/api/v1/orders', (req, res) => res.redirect(307, '/api/v2/orders'));Inspect HSTS in Chrome
If you see 307 Internal Redirect and didn't expect HTTPS, open chrome://net-internals/#hsts to query or delete the domain's HSTS entry. Check what your server really sends with curl -sI http://example.com.
Headers that matter with 307
- Location
- Where to repeat the request.
- Strict-Transport-Security
- The header behind Chrome's internal 307s. Once a browser has seen it, it upgrades
http://tohttps://locally formax-ageseconds.
307 vs similar status codes
- 302 Found: Temporary too, but browsers change POST to GET. 307 forbids that.
- 308 Permanent Redirect: The permanent version of 307: same method-preserving rule, but cacheable and permanent.
- 303 See Other: The opposite rule: always follow with GET. Used after form posts.
SEO impact of 307
Google treats a 307 like a 302: temporary, a weak canonical signal. Googlebot never sees Chrome's internal HSTS 307, so check what your server actually returns with curl or Search Console's URL Inspection tool.
Related status codes
302Found
The resource is temporarily at a different URL; keep using the original URL for future requests.
308Permanent Redirect
Permanently moved: repeat this and future requests at the Location URL without changing the method.
301Moved Permanently
The resource has a new permanent URL, given in the Location header.
Looking for another code? Search the full HTTP status codes list, or read which code your API should return in the REST API status codes guide.
Learn more
HTTP Status Codes for REST APIs: 200 vs 201 vs 204, 400 vs 422 vs 429
A practical guide to choosing the right HTTP status code in REST API design. Covers the most confusing pairs: 200 vs 201, 400 vs 422, 401 vs 403, and when to use 503 vs 429.
REST API Design Best Practices: A Practical Guide
The conventions that make REST APIs intuitive and consistent. Covers URL design, HTTP methods, status codes, versioning, pagination, and error responses.
CORS Explained: Why It Happens and How to Fix It
CORS errors happen when a browser blocks a request to a different origin. Learn how the Same-Origin Policy works, what preflight requests are, and how to configure CORS correctly in Express, FastAPI, and Nginx.
Frequently Asked Questions
What does 307 Internal Redirect mean in Chrome?▾
Chrome upgraded an http:// request to https:// on its own because the site uses HSTS (the Strict-Transport-Security header) or is on the HSTS preload list. No request reached the server and the server didn't send that redirect. It's normal and safe.
Why does Next.js return 307 instead of 301?▾
Next.js defaults to temporary redirects: redirect() and NextResponse.redirect() send 307, and next.config redirects with permanent: false send 307. For a permanent move use permanentRedirect() or permanent: true, which send 308.
Does a 307 redirect keep the POST body?▾
Yes, that's the point of 307: the client must repeat the request with the same method and body at the new URL. Browsers, fetch() and curl -L all do this. With 302, browsers switch POST to GET and drop the body.