301 vs 302 redirects (and 307, 308): which to use
Kofi Agyem, Founder and CEO, CloudzyroPublished · 5 min read
On this page
301 and 308 are permanent redirects, 302 and 307 temporary. How they differ, how Google treats each, and how to set them in nginx, Apache and Next.js.
1. The short answer
Use a 301 (or 308) when a page has moved for good, and a 302 (or 307) when the move is temporary. Permanent redirects tell browsers and search engines to use the new address from now on; Google moves the page's place in search results to the new address. Temporary redirects keep the old address as the real one.
The newer codes add one rule. 307 and 308 must keep the request's method and body, so a form POST stays a POST. With 301 and 302, browsers may change a POST into a GET, and in practice they do.
2. The four redirects at a glance
- 301 Moved Permanently: permanent; method may change to GET; cached by browsers by default.
- 302 Found: temporary; method may change to GET; not cached unless headers say so.
- 307 Temporary Redirect: temporary; method and body kept.
- 308 Permanent Redirect: permanent; method and body kept; cached by default.
There's also 303 See Other, which always tells the browser to fetch the new address with GET. It's the right answer after a form is submitted, so refreshing the result page doesn't send the form twice.
3. When to use which
- A page's address changed for good (new slug, new structure): 301 or 308.
- http to https, or non-www to www: 301 or 308.
- Moving to a new domain: 301 or 308 from every old page to its matching new page, not all to the home page.
- A short promotion, maintenance page or A/B test: 302 or 307.
- Sending visitors to a sign-in page or a language version: 302 or 307, since the original address is still the real one.
- APIs and forms that POST: 307 or 308, so the body isn't lost.
4. How redirects affect SEO
Google says it treats 301 and 308 the same, as a strong signal that the target should be the address shown in results, and 302 and 307 the same, as a weak signal. If a temporary redirect stays in place long enough, Google may start treating it as permanent anyway, but don't rely on that: say what you mean.
- Redirect to the closest match. Redirecting removed pages to the home page is treated as a soft 404.
- Avoid chains. Googlebot follows up to 10 hops, but every hop slows visitors down. Point old addresses straight to the final one.
- Update your own links and sitemap to the new addresses, so the redirect is only for outsiders.
- Keep redirects for a long time, a year or more, since links elsewhere rarely get updated.
JavaScript and <meta http-equiv="refresh"> redirects also work for Google, but server-side redirects are faster and clearer for everyone. For missing pages, see What is a 404 error?.
5. How to set redirects
nginx. Use return with the status code. It keeps the path and query when you include $request_uri.
# nginx: whole domain to www, permanently
server {
server_name example.com;
return 301 https://www.example.com$request_uri;
}
# One page, temporarily
location = /sale {
return 302 /summer-sale;
}Apache and cPanel hosting (`.htaccess`). Redirect handles simple cases; mod_rewrite handles patterns.
# Apache: one page, permanently
Redirect 301 /old-page /new-page
# Force https, permanently
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]Next.js. In next.config, redirects() with permanent: true sends 308 and permanent: false sends 307; use statusCode: 301 if you need the older code. In server code, redirect() sends 307 (303 inside a Server Action) and permanentRedirect() sends 308.
// next.config.ts
async redirects() {
return [
{ source: "/blog/:slug", destination: "/guides/:slug", permanent: true },
];
}Node and Express. res.redirect("/new") sends 302 by default. Pass the code for anything else: res.redirect(301, "/new").
WordPress and PHP. wp_redirect() sends 302 by default; pass 301 as the second argument. In plain PHP, header("Location: /new", true, 301); exit;. Redirect plugins are fine for many redirects; make sure they're set to 301 for permanent moves.
Cloudflare. Redirect Rules (and Bulk Redirects for long lists) let you pick 301, 302, 307 or 308 and whether to keep the query string. They run before the request reaches your server.
6. On Cloudzyro
When you add a domain to a Sites & Apps site, the bare domain (example.com) answers with a permanent 301 redirect to https://www.example.com, keeping the path and query, so both addresses work and search engines see one. See Custom domains and www vs non-www. Redirects for your own pages belong in your app or framework, as above. On Web Hosting, use .htaccess.
7. How to check a redirect
# Show each hop: status code and location
curl -sIL https://example.com/old-page | grep -i -E "^HTTP|^location"Each HTTP/ line is one hop; the last should be 200. More than one or two hops means a chain to clean up. In browser developer tools, tick Preserve log in the Network tab to see every redirect. Browsers cache 301s hard, so test changes in a private window. A 307 Internal Redirect there is Chrome applying HSTS, not your server.