Nginx Redirect Best Practices: Return 301 vs Rewrite for SEO and Performance


2 views

When configuring URL redirection in Nginx, developers often face the dilemma between using return versus rewrite directives. Let's examine the technical differences through concrete examples.


# Option 1: Using return directive
server {
    server_name example.com;
    return 301 $scheme://www.example.com$request_uri;
}

# Option 2: Using rewrite directive
server {
    server_name example.com;
    rewrite ^ http://www.example.com$request_uri? permanent;
}

The return directive is more efficient because:

  • It immediately terminates processing and returns to client
  • No regular expression matching occurs
  • Lower CPU overhead (benchmarks show ~15% faster response)

Both methods can achieve 301 (permanent) redirects, but implementation matters:


# Correct 301 redirect with return
curl -I example.com
HTTP/1.1 301 Moved Permanently
Location: http://www.example.com/

# Potential pitfall with rewrite
# (If not properly configured, might send 302 instead)

The original issue with rewrite showing 302 likely occurs because:

  1. The rewrite rule might be getting overridden elsewhere
  2. Browser cache interfering with redirect testing
  3. Missing ? after $request_uri in rewrite pattern

For most cases, this canonical solution works best:


server {
    listen 80;
    server_name example.com;
    return 301 https://www.example.com$request_uri;
}

server {
    listen 443 ssl;
    server_name www.example.com;
    # SSL configuration and other settings...
}

For complex redirect needs, combine both methods:


# Preserve query strings in redirects
if ($args ~* "^(.+)$") {
    rewrite ^/(.*)$ /newpath/$1?$args? permanent;
}

# Domain migration example
server {
    server_name olddomain.com;
    return 301 $scheme://newdomain.com$request_uri;
}

In Nginx configuration, both return and rewrite directives can handle redirections, but they operate differently at the processing level:

# Return directive (immediate response)
return 301 $scheme://www.example.com$request_uri;

# Rewrite directive (regex processing)
rewrite ^(.*)$ http://www.example.com$1 permanent;

For simple domain redirects (non-www to www or HTTP to HTTPS), return is more efficient because:

  • It doesn't involve regex pattern matching
  • Generates less CPU overhead
  • Provides clearer configuration intent
  • Consistent behavior across all clients

The 302 response you're seeing with rewrite might occur when:

# Problematic case (might get interpreted as 302)
rewrite ^ http://$host$request_uri? permanent;

# Working solution (explicit scheme)
rewrite ^ https://www.example.com$request_uri permanent;

Here's the optimal setup for www/non-www redirection:

server {
    listen 80;
    server_name example.com;
    return 301 $scheme://www.example.com$request_uri;
}

server {
    listen 80;
    server_name www.example.com;
    # Your main configuration here
}

Rewrite becomes valuable for:

  • Complex URL pattern changes (changing URL structures)
  • Conditional redirects based on query parameters
  • When you need to capture and reuse path components
# Example where rewrite is appropriate
rewrite ^/old-path/(.*)$ /new-path/$1 permanent;

Both methods properly implemented with 301 will preserve SEO value, but:

  • Return is faster (better for crawl budget)
  • Rewrite offers more flexibility for complex migrations
  • Always test with tools like Screaming Frog after implementation

Remember to clear your Nginx cache (nginx -s reload) after making changes and verify with curl -I to check response codes.