SiteError.comYour friendly guide to HTTP status codes
Status CodesBlog
  1. Home
  2. Blog
  3. Understanding HTTP 307 Temporary Redirect: The Method-Preserving Fix for 302, and Why Next.js Defaults to It

Understanding HTTP 307 Temporary Redirect: The Method-Preserving Fix for 302, and Why Next.js Defaults to It

August 6, 202610 min read
3xxRedirection

307 Temporary Redirect exists to fix a bug that HTTP never actually fixed — it just worked around it. 302 can silently turn a POST into a GET when a browser follows it, a quirk so old and so widespread that the spec eventually gave up correcting it and introduced 307 instead: a temporary redirect with a hard guarantee that the method and body survive. This post covers what 307 actually promises, how it differs from 301, 302, and 308, why Next.js quietly makes it the framework-wide default, and how to return it correctly.

What Is a 307?

A 307 tells the client that the resource it asked for is temporarily available at a different URI — and unlike 302, the client is required to keep using the exact same HTTP method when it follows the redirect.

The 307 (Temporary Redirect) status code indicates that the target resource resides temporarily under a different URI and the user agent MUST NOT change the request method if it performs an automatic redirection to that URI. — RFC 9110, Section 15.4.8

In plain English: this is a temporary redirect that guarantees the HTTP method stays the same. If you sent a POST, it remains a POST after the redirect, body and all. It's the direct successor to 302 for any redirect where changing the method would break something — an API call, a file upload, a form submission.

Unlike 302 (which might change POST to GET due to historical browser behavior), 307 guarantees method preservation. This makes it the right choice for API redirects, form submissions, or any case where changing the method would break functionality. Use 303 when you explicitly want POST to become GET.

Why 307 Exists: The 302 Method Bug

HTTP/1.0 called code 302 "Moved Temporarily," and the intent was that a redirect shouldn't change what the client was trying to do — just where it was trying to do it. But early browsers implemented 302 incorrectly: when a POST request received a 302, they replayed the redirect as a GET, dropping the body entirely. That bug shipped in so many clients that HTTP/1.1 couldn't fix it without breaking the web — so the spec renamed 302 to "Found," officially blessed the method-changing behavior as tolerated (MAY change the request method from POST to GET), and introduced two new, unambiguous codes instead of trying to repair the old one:

  • 303 See Other — explicitly always switch to GET, for the redirect-after-POST pattern.
  • 307 Temporary Redirect — explicitly never change the method, for everything else.

307 is, in effect, "302 with the method bug fixed" — same temporariness, but a guarantee 302 was never able to give.

307 vs 301 vs 302 vs 308

The 3xx redirect family splits along two independent axes: is the move permanent? and is the HTTP method guaranteed to survive?

CodeMeaningPermanent?Method preserved?Use when
301 Moved PermanentlyGone for goodYesNo (may become GET)Permanent URL change, SEO migration
302 FoundTemporarily elsewhereNoNo (may become GET)Temporary redirect of GET traffic; legacy compatibility
307 Temporary RedirectTemporarily elsewhereNoYesTemporary redirect where POST must stay POST
308 Permanent RedirectGone for goodYesYesPermanent move of API endpoints, form targets

307's closest relative is 302 — they mean the same thing about permanence, and differ only in the method guarantee, which is exactly the fix described above. Its other close relative is 308: both preserve the method, and they differ only in permanence, the same way 301 and 302 do. You can compare 302 vs 307 side by side, and the permanent half of this story is covered in understanding 301 redirects and understanding 308 Permanent Redirect.

When to Use 307

The cases where 307 is the right call all share one property: the redirect is temporary, and whatever method the client used matters:

  1. A temporary redirect that must preserve the HTTP method — POST stays POST, PUT stays PUT, with the body intact.
  2. Redirecting form submissions or API calls temporarily — a load balancer, a maintenance window, or a short-lived endpoint migration where losing the request body would silently break the call.
  3. Preferred over 302 for modern applications — any time you're writing new redirect logic and don't have a specific reason to want the method to change, 307 removes the ambiguity 302 carries.
  4. The original URL should keep being used for future requests — like 302, 307 doesn't ask clients to update bookmarks or treat the destination as the new canonical location.

Why Next.js Defaults to 307

This is the detail that makes 307 more than a spec curiosity for anyone building on Next.js: the framework's redirect() function returns a 307 by default (303 only inside Server Actions), and next.config.ts's redirects() uses 307 for permanent: false — specifically because of the POST-to-GET ambiguity described above. Next.js's own documentation frames this explicitly: 302 and 301 historically changed a POST to GET, which is undesirable for operations like creating a resource, so the framework's redirect primitives use 307 and 308 instead to guarantee the original method is preserved.

// app/dashboard/page.tsx — this sends a 307, not a 302
import { redirect } from "next/navigation";
 
export default async function Dashboard() {
  const session = await getSession();
  if (!session) {
    redirect("/login");
  }
  // ...
}
// next.config.ts — permanent: false emits a 307
const nextConfig = {
  async redirects() {
    return [
      {
        source: "/old-campaign",
        destination: "/new-campaign",
        permanent: false, // 307 Temporary Redirect
      },
    ];
  },
};
 
export default nextConfig;

NextResponse.redirect() follows the same convention — its status defaults to 307 if you don't pass one explicitly, which is worth knowing if you're writing a proxy or middleware redirect and expect a 302 by habit from other frameworks.

Returning 307 Correctly

Express / Node.js

Express defaults res.redirect() to 302, so getting a 307 means passing the status explicitly:

// Temporary redirect of a POST endpoint — use 307 so the method and body survive
app.post("/api/orders", (req, res) => {
  res.redirect(307, "/api/v2/orders");
});

Browsers and fetch will replay the exact method and body against /api/v2/orders, unlike what would happen with a bare res.redirect("/api/v2/orders") (a 302).

Next.js App Router

// app/go/route.ts — a Route Handler that issues a 307 explicitly
import { NextResponse } from "next/server";
 
export function GET(request: Request) {
  return NextResponse.redirect(new URL("/temporary-page", request.url), 307);
}

Since NextResponse.redirect() already defaults to 307, this line is equivalent to omitting the status entirely — but being explicit is worth it in code other developers will read, since 307 is easy to mistake for 302 at a glance.

NGINX

# Explicit temporary redirect that preserves the method
location /old-campaign {
    return 307 /new-campaign;
}

Unlike Express's res.redirect(), NGINX's return directive doesn't default to any particular redirect status — you always specify the code, so there's no accidental-302 trap here the way there is in application frameworks.

What the response should look like

HTTP/1.1 307 Temporary Redirect
Location: /alternative-endpoint

Same shape as a 302 — a Location header does the work, and the response typically carries no meaningful body. The client's browser or HTTP library is responsible for replaying the original method and body against the new Location.

307 and SEO

307's SEO behavior tracks 302 closely, because from a crawler's perspective the method-preservation guarantee is largely irrelevant — crawlers request pages with GET, so there's nothing for 307 to preserve that 302 wouldn't have preserved anyway:

  • Indexing — like 302, the original URL remains in the index. Google treats 307 as a temporary redirect and does not transfer ranking signals to the destination.
  • Crawl behavior — crawlers follow the redirect but expect the original URL to eventually serve content directly again, and continue re-crawling the original rather than replacing it with the destination.
  • Canonical signals — 307 is a weak canonical signal, the same as 302. Use it only for genuinely temporary redirects; for permanent changes, use 301 or 308 instead.
  • Google's treatment — Google treats 307 identically to 302 for SEO purposes. The method-preservation guarantee that makes 307 valuable to your application layer is invisible to a crawler using GET requests.

The practical takeaway: choose between 307 and 302 based on what your clients and API consumers need, not based on any SEO difference — there isn't one. The SEO decision that actually matters is temporary vs. permanent, which is the 307-vs-308 axis, not 307-vs-302.

Common Pitfalls

  1. Using 302 for a temporary redirect of a non-GET request. This is the exact bug 307 was created to avoid — a POST or PUT redirected with 302 can silently arrive at the destination as a bodyless GET. Use 307 whenever the method must survive.
  2. Assuming 307 changes the SEO story versus 302. It doesn't — Google treats them identically for indexing and ranking purposes. Reach for 307 for its method guarantee, not for any SEO advantage over 302.
  3. Leaving a "temporary" 307 in place indefinitely. Like 302, a long-lived 307 risks being reinterpreted by search engines as effectively permanent. If the move has become permanent in practice, switch to 308 deliberately.
  4. Reaching for 307 when you actually want the method to change to GET. After a successful form POST, redirecting to a confirmation page is a 303 situation, not 307 — 307 is for preserving the method, not for the classic redirect-after-POST pattern.
  5. Forgetting that Express still defaults to 302. Copying a res.redirect(path) call from GET-handling code into a POST handler carries the 302 default along with it — always pass the status explicitly when the method matters.

Wrapping Up

307 is the status code that makes "temporary redirect" mean the same thing for every HTTP method, not just GET. The rules of thumb:

  • 307 means temporarily elsewhere, and the method is guaranteed to survive — the fix for 302's historical POST-to-GET ambiguity
  • Reach for it whenever you're redirecting a POST, PUT, DELETE, or any non-GET request and the body or method matters
  • Its SEO behavior is identical to 302 — the method guarantee only matters to clients, not to crawlers
  • Next.js defaults its redirect primitives to 307 (and 308 for permanent redirects) for exactly this reason — treat that as the modern default, not just a framework quirk

For more, see our pages on 307 Temporary Redirect, 302 Found, and 308 Permanent Redirect. The permanent side of this story is covered in our understanding 301 redirects and understanding 308 Permanent Redirect posts, and you can compare 302 vs 307 side by side.

Full Reference

307 Temporary Redirect

The server sends this response to direct the client to get the requested resource at another URI with the same method.

Related Status Codes

🚪300Multiple Choices📦301Moved Permanently🔀302Found👀303See Other💾304Not Modified🕵️305Use Proxy↪️307Temporary Redirect🏠308Permanent Redirect
Back to Blog

Popular Status Codes

  • 200 OK
  • 301 Moved Permanently
  • 302 Found
  • 400 Bad Request
  • 401 Unauthorized
  • 403 Forbidden
  • 404 Not Found
  • 500 Internal Server Error
  • 502 Bad Gateway
  • 503 Service Unavailable

Compare Codes

  • 401 vs 403
  • 301 vs 302
  • 404 vs 410
  • 500 vs 502
  • Compare any codes →

Categories

  • Informational
  • Success
  • Redirection
  • Client Error
  • Server Error
  • NGINX
  • Cloudflare
  • AWS ELB
  • Microsoft IIS

Tools

  • Cheat Sheet
  • Status Code Quiz
  • URL Checker
  • API Playground
  • Blog

© 2026 SiteError.com. All rights reserved.