Redirects tell browsers and search engines that a page has moved. The status code you choose affects whether search engines transfer ranking signals (PageRank) to the new URL.
Key Takeaways
- 1301 = Permanent: Use for URL migrations, domain changes
- 2302 = Temporary: Use for A/B tests, temporary maintenance
- 3307/308 = Preserve HTTP method (important for forms)
- 4Redirect chains hurt page speed and dilute PageRank
- 5Google now passes full PageRank through 301 redirects
"The 301 (Moved Permanently) status code indicates that the target resource has been assigned a new permanent URI and any future references to this resource ought to use one of the enclosed URIs."
Redirect Status Codes
HTTP defines several redirect status codes, each with different semantics and SEO implications. Understanding the difference between 301 and 302 is critical, as using the wrong code can prevent your new URL from inheriting the ranking power of the old one.
The table below summarizes the four main redirect codes you will encounter. Pay special attention to the SEO impact column, as this is where the real differences matter.
| Code | Name | When to Use | SEO Impact |
|---|---|---|---|
| 301 | Moved Permanently | URL changed forever | Passes full PageRank |
| 302 | Found (Temporary) | Temporary move, coming back | May not pass PageRank |
| 307 | Temporary Redirect | Temporary, preserves method | May not pass PageRank |
| 308 | Permanent Redirect | Permanent, preserves method | Passes full PageRank |
Now that you understand the codes, let's look at how to implement redirects across different platforms and frameworks.
Implementation
The implementation varies by platform, but the core concept is the same: respond with the appropriate status code and a Location header pointing to the new URL. Most frameworks provide convenient abstractions so you do not need to handle headers manually.
// Next.js (next.config.js)
module.exports = {
async redirects() {
return [
{
source: '/old-page',
destination: '/new-page',
permanent: true, // 301
},
{
source: '/temporary-move',
destination: '/temp-page',
permanent: false, // 302
},
];
},
};
// Express.js
app.get('/old-page', (req, res) => {
res.redirect(301, '/new-page');
});
// Nginx
location = /old-page {
return 301 /new-page;
}
location = /temp-page {
return 302 /maintenance;
}Notice how each platform makes the distinction between permanent and temporary redirects clear. Next.js uses a boolean permanent property, Express uses the status code directly, and Nginx uses the return directive with the code.
One critical mistake to avoid is creating chains of redirects. This happens when you redirect A to B, then later redirect B to C, resulting in a chain.
Redirect Chains
Redirect chains occur when one redirect leads to another. This is surprisingly common on sites that have gone through multiple redesigns or CMS migrations without cleaning up old redirects. Each hop in the chain adds latency and historically diluted PageRank.
# BAD: Redirect chain
/page-v1 → 301 → /page-v2 → 301 → /page-v3 → 301 → /page-final
Problems:
- Slower page loads (multiple round trips)
- PageRank dilution (historically)
- Googlebot may stop following after ~5 hops
# GOOD: Direct redirect
/page-v1 → 301 → /page-final
/page-v2 → 301 → /page-final
/page-v3 → 301 → /page-finalThe solution is to always redirect to the final destination. When you create a new redirect, check if the destination itself redirects somewhere else. If so, skip the middle step and point directly to the final URL.
With the technical details covered, let's summarize when to use each redirect type based on real-world scenarios.
When to Use Each Code
The following table maps common scenarios to the appropriate redirect code. When in doubt, ask yourself: is this change permanent? If yes, use 301. If the old URL might come back, use 302.
| Scenario | Code | Why |
|---|---|---|
| URL permanently changed | 301 | Standard permanent redirect |
| Domain migration | 301 | Transfer all signals to new domain |
| HTTP to HTTPS | 301 | Permanent protocol change |
| Trailing slash normalization | 301 | Permanent consistency |
| A/B test redirect | 302 | Temporary, may revert |
| Geo-based redirect | 302 | User-specific, not permanent |
| Form submission redirect | 303/307 | Preserve or change method |
Note the 307 and 303 codes for form submissions. These preserve or change the HTTP method respectively, which matters when redirecting POST requests. Using 301 or 302 for POST requests can cause browsers to change the method to GET, potentially breaking form submissions.