The resource you requested has been permanently moved to a new URL. All future requests should use the new URL provided in the Location header. Search engines transfer ranking signals from the old URL to the new one.
HTTP 301 Moved Permanently is a redirection status code indicating that the requested resource has been permanently assigned a new URL. The server includes the new URL in the Location response header, and browsers automatically follow the redirect. Search engines interpret a 301 as a signal to transfer all ranking signals, link equity, and indexing priority from the old URL to the new one, making it the preferred redirect type for permanent URL changes.
The 301 status code is one of the most important tools in an SEO engineer's toolkit. When you restructure your website URLs, migrate to a new domain, or consolidate duplicate content, 301 redirects ensure that the authority your old pages accumulated through backlinks and user engagement is passed to their new locations. Without 301 redirects, users hitting the old URLs would see 404 errors, and search engines would treat the new URLs as entirely new pages with zero authority.
One important caveat about 301 redirects is that they historically allowed browsers to change the HTTP method from POST to GET during the redirect. While this behavior was not originally intended, it became so widespread that the HTTP specification was updated to reflect it. If you need a permanent redirect that strictly preserves the HTTP method, use 308 Permanent Redirect instead. For temporary URL changes where you want to preserve the method, use 307 Temporary Redirect.
Moving a website from one domain to another. A 301 redirect ensures users and search engines are sent to the new domain and that SEO value is preserved through the transition.
Restructuring your website URLs, such as changing from /blog/post-title to /articles/post-title. 301 redirects prevent broken links and maintain search engine rankings.
Upgrading your site from HTTP to HTTPS. A 301 from http://example.com to https://example.com signals search engines that the secure version is the canonical URL.
Enforcing a consistent URL format with or without trailing slashes. A 301 redirect from /about to /about/ or vice versa prevents duplicate content issues in search engines.
After setting up 301 redirects, update all internal links to point directly to the new URLs. This reduces redirect chains and improves page load performance.
Ensure 301 redirects go directly to the final destination. Chains like A to B to C slow down page loads and dilute SEO value. Each redirect adds latency and loses a small percentage of link equity.
Update your sitemap.xml to reference the new URLs and set canonical tags on the destination pages. This reinforces the new URL structure for search engine crawlers.
Check Google Search Console for crawl errors after implementing 301 redirects. Monitor the coverage report to ensure the new URLs are being indexed and the old ones are being dropped.
// Express.js — permanent redirects
const express = require('express');
const app = express();
// Single URL redirect
app.get('/old-page', (req, res) => {
res.redirect(301, '/new-page');
});
// HTTP to HTTPS redirect (middleware)
app.use((req, res, next) => {
if (req.headers['x-forwarded-proto'] !== 'https') {
return res.redirect(301, `https://${req.hostname}${req.url}`);
}
next();
});
// Trailing slash normalization
app.use((req, res, next) => {
if (req.path !== '/' && req.path.endsWith('/')) {
const newPath = req.path.slice(0, -1) + (req.url.includes('?')
? req.url.slice(req.url.indexOf('?')) : '');
return res.redirect(301, newPath);
}
next();
});
# Flask — permanent redirects
from flask import Flask, redirect, request
app = Flask(__name__)
# Single URL redirect
@app.route('/old-page')
def old_page():
return redirect('/new-page', code=301)
# HTTP to HTTPS redirect
@app.before_request
def force_https():
if request.headers.get('X-Forwarded-Proto') == 'http':
url = request.url.replace('http://', 'https://', 1)
return redirect(url, code=301)
# Trailing slash normalization
@app.before_request
def normalize_trailing_slash():
path = request.path
if path != '/' and path.endswith('/'):
return redirect(path.rstrip('/'), code=301)
A 301 is permanent and tells search engines to transfer all ranking signals to the new URL. A 302 is temporary and tells search engines to keep indexing the original URL. Use 301 for permanent URL changes and 302 for temporary situations like A/B testing or maintenance.
Keep 301 redirects active for at least one year, and ideally indefinitely. Search engines may take months to fully process the redirect, and external backlinks pointing to the old URL will continue to arrive for years.
Google has confirmed that 301 redirects pass full link equity to the destination URL. There was a time when some SEO value was lost in redirects, but Google updated their algorithm to pass 100% of PageRank through 301 redirects.
Individual 301 redirects do not hurt SEO, but redirect chains (A redirects to B redirects to C) can slow down page loads and cause Googlebot to stop following after a certain depth. Always redirect directly to the final destination.
Use 301 when users should be sent to a different URL. Use canonical tags when both URLs should remain accessible but you want search engines to consolidate ranking signals to one preferred version.
Get instant alerts when your endpoints go down. 60-second checks, free forever.
Start Monitoring Free →