Bulk Redirect Map After a Site Restructure

A practical guide to building a bulk redirect map: extracting old URLs from logs and Search Console, one-to-one mapping, batch testing with curl, and avoiding loops.

6 min Updated 23 Sep 2026

You've redesigned the site, the category structure has changed, and now Search Console is showing several hundred 404 errors a day. If you don't start building a redirect map today, every day that passes erodes part of the authority of your old links and your incoming traffic. The good news is that this is a one-time job — as long as you go about it the right way.

First, build the list of old URLs from real data

Most teams do this step from memory and then wonder why the traffic never came back. The URLs that actually got visits are recorded in three places: the web server access log, the Search Console performance report, and external backlinks. Extract all three and put them into a single CSV file.

From the server log, isolate only the old successful requests. If the web server is Nginx:

awk '{print $7}' /var/log/nginx/access.log \
  | grep -E '^/(blog|products|category)/' \
  | sort | uniq -c | sort -rn | head -500

The first column of this command's output is the hit count and the second is the path. Take the second column, prepend the domain to it, and add it to the list. For Search Console, go to the Pages section of the Performance report, set the range to 16 months, and download the CSV export. The "URL" column is exactly what you need.

One point that rarely gets mentioned: keep URLs with query parameters separate. Redirecting /product?id=42 to a static page is almost always wrong, because that parameter may take on a different meaning later.

One-to-one mapping, not redirecting everything to the homepage

There's a temptation to redirect everything to /. Technically it works, and from an SEO standpoint it's a disaster. Google interprets mass redirects to the homepage as soft 404s and does not pass link authority. Every old URL should go to its closest topical equivalent.

To do this, build a two-column table: source and destination. The source must be the full path without the domain, and the destination must be the final, canonical URL. If a page has no equivalent, redirect to the closest parent category, not to the homepage.

Status of old URLCorrect destinationStatus code
Has an exact equivalentThe same new page301
Merged into a new categoryThe new category page301
Completely removedThe closest parent category301
Temporarily under maintenanceThe same path302
Duplicate content removedThe canonical version410 or 301

The 410 code is for pages that truly no longer exist and that you don't want to have an equivalent. Its difference from 404 is that it tells Google the removal is intentional and permanent, so it drops out of the index faster. But if that page has valuable backlinks, 410 is wrong; you should use 301.

Where to implement the map: web server or application

There are two main places to apply redirects, and choosing between them affects speed and maintenance. If the number of rules is under a few hundred and the structure is fixed, the web server layer is the right choice. If the rules come from a database or a content manager needs to edit them without SSH access, the application layer makes more sense.

In Nginx, write the rules in the server block. For bulk redirecting a pattern, use map, which is faster than a chain of if statements:

map $uri $redirect_target {
    /old-blog/post-1    /blog/new-post-1;
    /old-blog/post-2    /blog/new-post-2;
    /category/php       /categories/php-hosting;
    default             "";
}

server {
    listen 443 ssl;
    server_name example.com;

    if ($redirect_target) {
        return 301 $redirect_target;
    }
}

In Apache, the equivalent is the .htaccess file:

Redirect 301 /old-blog/post-1 /blog/new-post-1
RedirectMatch 301 ^/category/php/?$ /categories/php-hosting

The cost of this approach: every added rule is one extra comparison on every request. With a few thousand rules, the latency becomes noticeable. The practical solution is to put high-traffic rules at the top of the file and keep rare rules in a separate file with RewriteMap. If you're working on Linux hosting, before adding thousands of lines to .htaccess, consult support about file size limits and processing load.

Test in batches before applying

Applying the map to a live site without testing is the same mistake that takes a site offline for several hours. First test on a staging environment or by changing the Host header. The simplest way is to test with curl against the list of sources:

while read -r src dst; do
  code=$(curl -s -o /dev/null -w "%{http_code}" -I "https://example.com$src")
  loc=$(curl -s -o /dev/null -w "%{redirect_url}" -I "https://example.com$src")
  echo "$src -> $code -> $loc"
done < redirects.txt

The correct output looks something like this:

/old-blog/post-1 -> 301 -> https://example.com/blog/new-post-1

If you see 200 instead of 301, the rule wasn't applied. If you see 302, the code was written wrong somewhere. If you see a chain of 301s, the destination itself is also being redirected, and that's exactly what needs to be removed.

This is where people go wrong

The most common mistake I've actually seen: the HTTP-to-HTTPS redirect and the new-structure redirect are applied at the same time and without ordering, creating a loop. The sign is that the browser shows ERR_TOO_MANY_REDIRECTS and curl with -L stops after 20 hops. The cause is usually that the HTTPS rule is placed after the structure rule, and the destination of the second redirect points back to the HTTP version. The correct order is: first HTTP to HTTPS, then the structure. To get through this step without a loop, read the guide on installing SSL on hosting and forcing HTTPS without a redirect loop before writing the rules.

The second mistake, which is seen less often but is more painful: redirecting URLs that are still in the sitemap. The result is that Google crawls those same URLs every day, gets a 301, and crawl budget is wasted. After applying the map, update the sitemap too.

What to monitor after applying

A redirect map is a living file, not a finished task. In the first two weeks after applying it, check the Pages report in Search Console daily. If the number of 404 URLs goes up, you've missed part of the map. If the number of "Page with redirect" goes up but traffic doesn't come back, the destinations don't have the right topical equivalents.

One number worth measuring: server response time for redirected requests. If the TTFB for these requests goes above a few hundred milliseconds, you've probably stockpiled too many rules in .htaccess, or the server needs more resources. For high-traffic sites, moving to a dedicated server and implementing redirects at the Nginx layer instead of Apache makes a noticeable difference in that very number.

To check that redirects are working correctly and that DNS and the network path aren't causing problems, use the DNS and network lookup tool. If you want to see how headers behave in a real environment before the final rollout, the free webmaster tools are a faster option than setting up staging.

Frequently asked questions

What's the difference between a 301 and a 302 redirect in a redirect map?

A 301 means a permanent move and passes link authority to the destination. A 302 means a temporary move and Google keeps the source URL in the index. For a site restructure, always use 301. 302 is only for temporary cases like maintenance or A/B testing.

If you've mistakenly used 302 and later change it to 301, that's fine; just know that until then, link authority hasn't been passed.

Should I redirect all old URLs?

No. Only URLs that had visits or backlinks are worth redirecting. URLs with no visits can be left to 404 or given a 410. Redirecting thousands of worthless URLs just makes the rules file heavy and hard to maintain.

How do I tell if redirects have looped?

Use curl -sIL https://example.com/old-path to see the header chain. If you see more than two or three hops, or the browser shows ERR_TOO_MANY_REDIRECTS, you have a loop. The cause is almost always the wrong ordering of the HTTP/HTTPS and structure rules.

Should I write the redirect map in Nginx or .htaccess?

If you have full control of the server, Nginx is the better choice because the rules are kept in memory and the file isn't read on every request. If you're on shared hosting and don't have access to the Nginx config, .htaccess is the only option. In either case, keep the source and destination list separate from the config so the next migration is easy.

Was this page helpful?