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


12 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.