Redirect Status Codes: 301, 302, 307, 308 and More

Michel BardelmeijerMichel Bardelmeijer

Michel Bardelmeijer is Tech Lead and Sales at redirect.pizza, where he helps DevOps and IT teams solve domain redirect challenges at scale. Michel has guided organizations like SD Worx, Zurich Airport and Harvard through complex redirect scenarios involving thousands of domains.

Have questions about bulk redirects, HTTPS migrations, or domain consolidations? Connect with Michel on LinkedIn or reach out to the redirect.pizza team.

A 302 where you needed a 301 keeps the old URL in Google's index for months. The status code you choose decides what happens to your HTTP method, your rankings, and your API calls. Get it wrong and the damage shows up later, in your index or your error logs. Here's what each code does, and when to use which.

The two you already know: 301 (permanent) and 302 (temporary) handle most redirects. 307 and 308 do the same job with one extra rule: the HTTP method must not change. 303 forces a GET after any other method, which prevents duplicate form submissions. 304 sits in the 3xx range but is a caching response, not a redirect. The rest are dead.

This article covers each code in detail, including how Google handles it. For the full picture of how redirects work across every type and use case, see our URL redirects complete guide.


Key Takeaways

  • 301 and 302 cover 99% of redirect needs. 307 and 308 exist for cases where the HTTP method must not change between the original request and the redirect.
  • The difference between 301 vs 308 (and 302 vs 307) is method preservation. 301 and 302 may convert a POST request into a GET. 307 and 308 keep POST as POST, PUT as PUT, DELETE as DELETE.
  • 303 See Other forces the redirected request to use GET. Use it after a POST form submission to prevent accidental resubmission on refresh.
  • 304 Not Modified sits in the 3xx family but is not a redirect. It tells the client to use its cached version of a resource.
  • HSTS-enabled browsers internally issue a 307 to upgrade HTTP requests to HTTPS before any network call happens. This is part of how secure browsing works, not something you configure.

A globe ringed with 301, 302, 307, and 308 labels, introducing the redirect status codes that matter.

The 3xx family at a glance

The 3xx class of HTTP status codes signals that further action is needed to complete the request. Most of the time, that action is following a Location header to a new URL. Sometimes, as with 304, it means using a cached copy instead.

Here is the full family, defined across RFC 7231 (HTTP semantics), RFC 7232 (conditional requests, for 304), and RFC 7538 (which added 308 in 2015).

CodeNameWhat it tells the clientHow often used
300Multiple ChoicesMultiple representations available, pick oneAlmost never
301Moved PermanentlyPermanent move, update bookmarks and search indexesMost common
302FoundTemporary move, keep original URL in indexesVery common
303See OtherFetch a different resource using GETSpecialized (form submissions)
304Not ModifiedResource has not changed, use cached copyCommon (but not a redirect)
305Use ProxyAccess resource through a proxyDeprecated for security reasons
306(Unused)Reserved, no longer usedNever
307Temporary RedirectTemporary move, preserve HTTP methodSpecialized (APIs, HSTS)
308Permanent RedirectPermanent move, preserve HTTP methodSpecialized (API migrations)

Three observations from this table that matter in practice. 305 and 306 are dead. You will not implement them. 304 is not actually a redirect, even though it sits in the 3xx range. And the difference between the "common" codes (301, 302) and the "specialized" ones (307, 308) is whether the request method can change during the redirect.


300 Multiple Choices

The 300 code is the theoretical "here are several options, you choose" response. The server returns a list of representations (different file formats, languages, or versions), the client picks one.

Almost nobody implements this. Modern content negotiation runs through Accept headers and 200 responses. If you see a 300 in production, treat it as a curiosity, not a configuration to copy.


301 Moved Permanently

The 301 is the default permanent redirect. It tells browsers, search engines, and any other client that the resource has moved for good. Future requests should go to the URL in the Location header. Search engines update their indexes accordingly.

A 301 also allows the client to change the request method from POST to GET when following the redirect. RFC 7231 documents this explicitly, and browsers have done it for decades. For most use cases (page redirects, domain migrations, URL structure changes) that doesn't matter, because the original request was a GET anyway. For API endpoints or form submissions, it can break things in ways that are hard to spot, which is why 308 exists.

For the full breakdown of 301 redirects, including when to use them and how they affect SEO, see what are 301 redirects.


302 Found

The 302 is the default temporary redirect. It tells clients the resource lives at a different URL for now but will be back. Search engines keep the original URL in their indexes rather than swapping it for the redirect target.

Like the 301, the 302 may convert a POST to a GET during the redirect. This caused so much confusion in the early web that RFC 7231 added two separate codes to make the behavior explicit: 303 (always GET) and 307 (method preserved).

For a side-by-side comparison of 301 vs 302 redirects, see 301 vs 302 redirects explained.


303 See Other

The 303 is the most misunderstood code in the redirect family. It exists to solve one specific problem: duplicate form submissions.

Here is the problem. A user submits a form using POST. The server processes it, creates the order, and charges the card. The browser then shows a confirmation page. If the user refreshes that page, the browser re-sends the original POST, which submits the form again. Two orders, two charges, one frustrated customer.

303 fixes this. After processing the POST, the server returns a 303 redirect pointing to a confirmation URL. The browser follows that redirect using GET (always, no matter what the original method was). The user lands on a GET-based confirmation page. A refresh re-issues the same GET. No duplicate submission, no double charge.

The flow looks like this:

  1. Client sends POST /orders with form data.
  2. Server processes the order.
  3. Server returns 303 See Other with Location: /orders/12345.
  4. Browser follows with GET /orders/12345.
  5. User sees the confirmation.
  6. Refresh just re-issues the GET.

You rarely set up 303 by hand. Most web frameworks issue it automatically when you call redirect() after handling a POST. The pattern even has a name: Post-Redirect-Get, or PRG. Most developers encounter 303 only when debugging a form flow or working with REST APIs that need explicit method changes.


304 Not Modified

The 304 sits in the 3xx range but is not actually a redirect. It is the standard answer to a conditional GET request, where the client sends an If-Modified-Since or If-None-Match header asking "has this resource changed since I last fetched it?" If the answer is no, the server returns 304 with no body. The client uses its cached copy.

This is how browser caching works under the hood, and why a returning visitor loads pages faster than a first-time visitor. The asset is already in the browser cache, the server confirms it has not changed, and the browser uses the local copy instead of downloading it again.

Some redirect-checking tools list 304 alongside the redirect codes because they share the 3xx range. Technically correct, practically misleading. A 304 is not a redirect, it is a caching signal. We mention it here because the confusion shows up in audits and onboarding questions often enough to warrant a paragraph.


307 Temporary Redirect

If 302 had a stricter sibling, the 307 would be it. Both signal a temporary move. The difference is that 307 tells the client to follow the redirect using the same HTTP method as the original request. A POST stays a POST. A PUT stays a PUT. A DELETE stays a DELETE.

That sounds like a small detail until you are migrating an API. Picture a billing service that handles POST /api/v1/charges. You move the endpoint to /api/v2/charges and set up a temporary redirect during the transition. With a 302, browsers and some API clients will convert the redirect into GET /api/v2/charges, which is not a valid endpoint, and the charge quietly fails. With a 307, the POST gets re-sent to the new URL with its body intact.

307 has a second job that most teams never see directly. When a browser supports HSTS (HTTP Strict Transport Security) and visits a site over HTTP, the browser internally issues a 307 redirect to upgrade the connection to HTTPS before any network request is made. This shows up in DevTools as "307 Internal Redirect" with a Non-Authoritative-Reason: HSTS header. There is no server response involved. The redirect happens entirely in the browser. We cover this in detail in the HSTS section further down.

For SEO purposes, 307 behaves like 302: search engines keep the original URL in their indexes. If you want link equity (the ranking signal that flows from one URL to another through a redirect) to transfer permanently, use 301 or 308 instead. For details on how this affects rankings, see are redirects bad for SEO.


308 Permanent Redirect

308 does for 301 what 307 does for 302: it adds method preservation.RFC 7538 added it to the standard in April 2015 specifically to fix the ambiguity around POST-to-GET conversion in 301 redirects. From the spec: "The user agent MUST NOT change the request method if it performs an automatic redirection to that URI."

Two practical implications:

  1. 308 is the right code for permanent API migrations. When your API moves from one domain to another, or one version to another, 308 guarantees that POST, PUT, and DELETE calls keep their methods and bodies intact. A 301 doesn't give you that guarantee.
  2. Google treats 308 as equivalent to 301 for SEO purposes. Both transfer link signals to the new URL. Both signal a permanent move that should update the search index. There is no SEO penalty for using 308 instead of 301.

So why does 301 still dominate? History and inertia.

The 301 has been around since HTTP/1.0 in 1996. Every web server, CMS, and migration tool defaults to it. 308 is newer (2015), and many tools require explicit configuration to issue it. For content migrations (pages, posts, marketing sites), 301 is fine. For API migrations, 308 is the safer default.

Method preservation compared: a 301 turns a POST into a GET and discards the body, a 308 keeps the POST and its body intact.

Most teams migrating an API blindly copy their existing 301 rules and break every POST endpoint on day one. They don't notice because the GET requests still work and the monitoring stays green. The fix isn't more documentation, it's one line: use 308 for API moves where the method must be preserved. Same SEO signal as 301, none of the quiet method conversion.

Michel Bardelmeijer, Tech Lead at redirect.pizza


Redirect code decision matrix

The fastest way to pick the right redirect code is to answer two questions. Is the move permanent or temporary? Does the HTTP method need to be preserved?

SituationPermanentTemporary
Method may change (standard web pages, marketing sites, domain moves)301302
Method must be preserved (APIs, form posts, payment flows)308307
Always GET after a POST (form submission confirmation)n/a303

Use 301 for the standard case: moving a website to a new domain or restructuring URLs. Use 302 when running an A/B test or a temporary maintenance redirect. Use 308 when migrating an API where calls must keep their methods. Use 307 when routing API traffic temporarily during a deployment. Use 303 specifically for form submission flows where you want to prevent duplicate posts.

If you find yourself debating between 301 and 308 for a page-level migration, default to 301. Method preservation doesn't matter for GET requests, and 99% of page traffic is GET.


HSTS and the 307 internal redirect

Here's how it actually works.

HSTS (HTTP Strict Transport Security) is defined in RFC 6797. It lets a server tell browsers "from now on, only connect to me over HTTPS." The browser receives a Strict-Transport-Security header on a successful HTTPS response and stores the policy with an expiration. The next time the user types http://yourdomain.com or clicks an HTTP link, the browser doesn't send the HTTP request at all. It internally rewrites the request to HTTPS before any network call.

In DevTools, this appears as a 307 Internal Redirect with a Non-Authoritative-Reason: HSTS header. The response is not from your server. It is in fact the browser talking to itself.

An HSTS 307 internal redirect upgrading http to https inside the browser, with no network request sent.

Why 307 and not 301 or 308? Because the HSTS policy has an expiration. The redirect is temporary in spec terms, even when the policy lasts two years. 307 also preserves the HTTP method, which matters for HTTPS upgrades of POST requests like login forms accidentally submitted over HTTP.

Three practical implications:

  1. Googlebot doesn't see HSTS 307s. They happen entirely in the browser. Crawlers that do not support HSTS just follow your server-side HTTP-to-HTTPS redirect, which should be a 301.
  2. If you see "307 redirect loops" in your testing tools, the cause is usually conflicting HSTS and server-side redirect rules, where both the browser and the server are trying to manage the upgrade. The fix is to make sure the server only redirects on the HTTP port.
  3. You can detect HSTS 307s in Screaming Frog: as of version 8.0 it reports them with Status: HSTS Policy and Redirect Type: HSTS Policy.

How Google's crawler interprets each code

Google's official documentation is direct on this. Per Google Search Central, server-side redirects (HTTP 301/308 for permanent, 302/303/307 for temporary) are preferred over client-side ones like meta refresh and JavaScript. Within the server-side family, the codes split into two buckets for indexing purposes.

Permanent redirects (301 and 308) signal that the new URL should replace the old one in search results. Google consolidates link signals to the target URL and treats it as the canonical version (the URL Google considers the "main" one when several URLs serve similar content). The two codes are equivalent for SEO. There is no ranking penalty for choosing 308 over 301.

Temporary redirects (302, 303, and 307) signal that the source URL should stay in the index. Google may still follow the redirect to crawl the destination, but it doesn't consolidate ranking signals or remove the original URL from search results. Use a 302 by mistake for a permanent move, and Google eventually figures it out (after weeks or months of the redirect being in place) and treats it as a 301. That works, but it is slow and unreliable. Pick the right code the first time.

A few practical notes

Googlebot follows redirect chains up to around 10 hops before giving up. If you suspect chain issues, see the article redirect chains and loops. HSTS-307s are invisible to Googlebot, since the crawler doesn't implement HSTS the same way as a browser. And meta refresh redirects with a 0-second delay are treated as permanent by Google, but they pass weaker signals and load slower than a true server-side 301.


Implementation across DNS server-side and application layers

Where the redirect lives in your stack determines which codes are available and how the redirect performs.

DNS-level redirects happen at the edge, before any web server is involved. Services like redirect.pizza resolve the destination URL at the DNS layer and return the response from a global edge network. The codes available depend on the provider. redirect.pizza supports 301, 302, 307, and 308 as configurable options, plus frame and meta refresh as alternatives. DNS-level redirects sidestep the certificate management, server configuration, and chain accumulation that pile up around self-hosted redirect setups. For the architectural comparison, check DNS-level vs server-side redirects.

Server-side redirects happen at the web server layer (Apache, nginx, IIS) or CDN layer (Cloudflare, Fastly). All redirect codes are technically available, though the syntax varies per server and the default for "permanent" rules is usually 301 rather than 308. Server-side gives full control over the response but adds the burden of certificate provisioning, configuration files, and the risk of stacking rules into chains across multiple layers.

Application-level redirects happen inside your application code (PHP, Node.js, Rails, Django, and similar). This is where 303 lives. Frameworks issue 303 automatically after form processing as part of the PRG pattern. Application-level redirects also handle conditional logic that DNS or server rules cannot express. Things like "redirect logged-in users to the dashboard, send anonymous users to login." The cost is latency. The request hits your application before getting redirected, which adds processing time and load.

The right layer depends on the redirect. Domain-to-domain redirects belong at the DNS or edge layer because they should not require backend processing. Path-level page redirects within a single site belong at the server or application layer. API migrations belong wherever your routing logic lives, but should use 308 (permanent) or 307 (temporary) instead of 301 or 302.


Try redirect.pizza on your own domains

Start configuring 301, 302, 307, and 308 redirects on redirect.pizza in under 5 minutes. Get started for free.


Frequently Asked Questions

Both preserve the HTTP method during a redirect. The difference is permanence. A 307 is temporary, which means search engines keep the original URL in their indexes. A 308 is permanent, which means search engines replace the original URL with the redirect target. Use 307 for temporary API routing or maintenance scenarios. Use 308 for permanent API migrations where the method (POST, PUT, DELETE) must not change.

Use a 303 after processing a POST request when you want the browser to fetch the next page with GET. The standard case is the Post-Redirect-Get pattern: a user submits a form, the server processes it, and the response redirects to a confirmation URL using 303. A refresh of the confirmation page re-sends a GET instead of resubmitting the POST. This prevents duplicate form submissions, double charges, and the "do you want to resubmit this form?" browser warning.

redirect.pizza supports 301, 302, 307, and 308 as configurable redirect types, plus frame and meta refresh as alternatives. The default for new redirects is 301 (permanent). The redirect type can be changed per source URL in your redirect settings. 303 is not a configurable option in redirect.pizza because it is an application-layer redirect typically issued by your web framework after handling a POST request, not a DNS-level redirect that fits the redirect.pizza model. 304 is not a redirect and is not part of the redirect.pizza feature set.

Pricing Background
Domain redirects delivered hassle-free

Get started right away

  • Free plan
  • No creditcard required
Serving millions of redirects for
Warner Bros.
Harvard
CalTech
Red Bull
Zurich Airport
Nando's
Jaguar
Bam
Kneipp
Culture Gouv FR
SD Worx
Visma
team.blue
ElevenLabs
SRF
Unit4
Ascension
Norlys
Concept2
Teamleader
Chargify
JBS SA
Hirslanden
Dansk Erhverv
Wunderman Thompson
Lerner Publishing Group
RGF Staffing
Apollo
IU
Chabad
MCC
Warner Bros.