DEVESSENTIALS

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.

3xx · RedirectionRFC 9110 §15.4.8

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 Redirect for http:// URLs on HSTS sites. That redirect never left the browser: the domain sent Strict-Transport-Security earlier 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 Redirect when 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 POST bodies intact.
  • CORS: a preflight OPTIONS request 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 201

Choose 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:// to https:// locally for max-age seconds.

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

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

Browse all developer guides →

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.