After a site reorg you need old links to keep working. Reach for return for fixed paths and rewrite only when you must capture part of the URL.
One page moved — exact match, cheapest:
location = /old-page {
return 301 /new-page;
}
A whole section moved — capture the rest of the path with rewrite:
# /blog/anything -> /articles/anything
rewrite ^/blog/(.*)$ /articles/$1 permanent;
permanent means 301; redirect means 302. The $1 is the captured group. rewrite keeps the query string automatically unless you end the replacement with ?.
Redirect to another domain, preserving the path:
location /docs/ {
return 301 https://docs.example.com$request_uri;
}
Add or remove a trailing slash consistently:
# Force a trailing slash on a known directory-style path:
location = /shop {
return 301 /shop/;
}
Guidance:
- Prefer
return— it’s explicit and fast. Userewriteonly for pattern captures. rewrite ... lastre-runs location matching (internal rewrite, no redirect sent);rewrite ... permanent/redirectsends a real 3xx to the browser. Don’t confuse them.- Avoid
iffor redirects where alocationwill do —locationmatching is clearer and avoidsifedge cases. - Verify without a browser cache getting in the way:
curl -sI https://example.com/blog/hello | grep -i location
# location: https://example.com/articles/hello