Free tool 301 redirect generator for .htaccess, Nginx and more
Paste one redirect per line, old address then new, and copy rules for Apache, Nginx, Cloudflare, Vercel or Netlify. Before writing a single rule the tool checks the whole list: redirects that point at another redirect, loops, the same URL sent to two places, and trailing-slash twins.
- 7 output formats
- Chains flattened, loops blocked
- Runs locally
Build redirect rules from a list
The example is a small site migration with one chain, one conflicting row, a URL with a query string and an old domain. Paste your own list, for example two columns copied from a spreadsheet.
Old then new, separated by a space, tab, comma or ->. Paths (/old) or full URLs. Add 301, 302, 307 or 308 at the end of a line to override the status for that row.
301 or 308 for permanent moves. 302 or 307 only for genuinely temporary ones.
What happens to ?utm_source=… and other parameters on the old URL.
Used for Cloudflare (which needs a host) and to tell your own URLs from other domains.
Redirects
6
Written to the rules
Chains
1
Found in the list
Rows skipped
1
Errors, duplicates, loops
# Generated by TapCub redirect generator – put in .htaccess at the site root (mod_rewrite)
RewriteEngine On
RewriteRule ^old-pricing/?$ /pricing [R=301,L]
RewriteRule ^blog/2019/seo-tips/?$ /guides/seo [R=301,L]
RewriteRule ^blog/seo-tips/?$ /guides/seo [R=301,L]
RewriteCond %{QUERY_STRING} ^id=42$
RewriteRule ^products/?$ /products/blue-widget [R=301,L,QSD]
RewriteRule ^about-us/?$ /about [R=301,L]
RewriteCond %{HTTP_HOST} ^old-shop\.example\.net$ [NC]
RewriteRule ^sale/?$ https://example.com/deals [R=301,L]
Copy into the file, or download it. Test on a staging site first, then check a few old URLs return the right status.
Checks
- ErrorLine 6"/about-us" is already redirected to /about on line 5. Only the first is used: one URL can only go to one place.
- NoteLine 2Chain flattened: "/blog/2019/seo-tips" now goes straight to /guides/seo instead of via /blog/seo-tips/.
Version v1.0Updated Update history
What the checks catch before you deploy
A redirect list built up over years of edits is rarely clean. These are the problems the tool looks for across the whole list, not line by line.
Chains
A → B → C: the old URL redirects to a page that redirects again. Each hop adds a round trip, and Google’s crawlers follow up to 10 hops before giving up. With “point chains at the final URL” on, A is written to go straight to C.
Loops
A → B and B → A, or a longer circle. Browsers stop with “too many redirects”. Rows in a loop are left out until you decide where the content really lives.
Conflicts and duplicates
The same old URL listed twice with different targets. Servers use the first match, so the second line never works. Nginx even refuses to start when two identical location = blocks exist.
Trailing slashes and query strings
/old and /old/ are different URLs to a server. The tool can cover both. Parameters such as utm_source are passed through by default, so campaign tracking survives the redirect.
Google treats 301 and 308 as strong signals that the new URL should be indexed, and 302 and 307 as weak ones. Keep redirects in place for at least a year after a move; links and bookmarks keep arriving long after.
Four steps to a safe migration
The rules are the easy part; testing is what prevents lost traffic.
-
1
List old and new URLs
Export the old URLs from analytics, Search Console or a crawl, and map each to its closest new page. Avoid sending everything to the home page.
-
2
Paste and pick the platform
Choose where the site runs. For a CDN in front of the server, rules at the CDN (Cloudflare) run before the request reaches your server.
-
3
Fix what the checks report
Resolve conflicts and loops, let the tool flatten chains, then copy or download the file.
-
4
Deploy and test
Reload the server config (for Nginx:
nginx -tfirst), then open a few old URLs or runcurl -Ito confirm the status and Location header.
One redirect, five platforms
The same rule, /old-pricing → /pricing with a 301 and the query string kept, written for each target. Exact matching is used everywhere, so /old-pricing-2024 is not caught by accident.
- Apache mod_alias
Redirectmatches by prefix (/old also catches /old/anything), so the tool usesRedirectMatchwith an exact pattern - In .htaccess a RewriteRule pattern has no leading slash
- Nginx
returndoes not keep the query string by itself;$is_args$argsadds it - Vercel:
permanent: truemeans 308; usestatusCode: 301for a 301
| Platform | Rule | Query string |
|---|---|---|
| Apache (mod_rewrite) | RewriteRule ^old-pricing/?$ /pricing [R=301,L] | Kept by default; QSD drops it |
| Apache (mod_alias) | RedirectMatch 301 "^/old-pricing/?$" "/pricing" | Always kept |
| Nginx | location = /old-pricing { return 301 /pricing$is_args$args; } | Only with $is_args$args |
| Cloudflare Bulk (CSV) | example.com/old-pricing,https://example.com/pricing,301,TRUE,… | PRESERVE_QUERY_STRING column |
| Vercel | { "source": "/old-pricing", "destination": "/pricing", "statusCode": 301 } | Always forwarded |
| Netlify | /old-pricing /pricing 301 | Forwarded automatically |
What the checks do with the sample list
Seven lines go in; six rules come out. Here is what happened to each problem row.
| Line | Input | Result |
|---|---|---|
| 2–3 | /blog/2019/seo-tips → /blog/seo-tips → /guides/seo | Chain flattened: line 2 now goes straight to /guides/seo |
| 3 | /blog/seo-tips/ (with slash) | Matches /blog/seo-tips too, which is why line 2 was a chain |
| 4 | /products?id=42 | RewriteCond on the query string; the old parameter is dropped |
| 6 | /about-us → /company | Skipped: line 5 already sends /about-us to /about |
| 7 | https://old-shop.example.net/sale | Extra RewriteCond on HTTP_HOST for the old domain |
Switch the platform to Cloudflare Bulk Redirects and line 4 is reported instead: bulk lists cannot match query strings.
Redirect mistakes that cost traffic
Most come from writing rules one at a time without looking at the whole list.
Leaving chains in place
Every migration adds a hop. After three redesigns an old link may bounce four times. Re-point old rules at the current URL.
Sending everything to the home page
Google may treat a redirect to an unrelated page as a soft 404. Map each URL to its closest equivalent, or let it 404.
Using 302 for a permanent move
302 tells search engines the old URL is coming back, so they may keep it indexed. Use 301 or 308.
Removing redirects too soon
Backlinks, bookmarks and old emails keep sending visitors for years. Keep the rules at least a year, ideally indefinitely.
Find the URLs that need a redirect
The hard part of a redirect map is knowing which old URLs still get visits. TapCub shows them, and lets you check the traffic after the move.
404s with the referrer
Broken URLs people still reach, with the page or site that sent them: the list to redirect first.
Learn moreCrawler errors
The crawl-health table counts 404s and 5xx per search engine and AI crawler, separately from human visits.
Learn moreSearch traffic after the move
Search Console and Bing data by page, with alerts when a page starts losing traffic.
Learn moreRedirect generator questions
Still have a question?
Chat with the team behind TapCub — we usually reply within a few hours on business days.
What is a 301 redirect?
An HTTP response with status 301 and a Location header that tells browsers and search engines the page has moved permanently. Search engines then index the new URL and consolidate signals there. 308 means the same but also keeps the request method (a POST stays a POST).
301 or 308? 302 or 307?
Google treats 301 and 308 the same: permanent, a strong signal. 302 and 307 are temporary, a weak signal. Use 301 for normal page moves; 308 matters only when forms or APIs POST to the old URL. Use 302 or 307 only for short-term redirects such as maintenance.
How do I add a 301 redirect in .htaccess?
Choose the Apache option, paste the list and put the result at the top of the .htaccess file in your site root. The RewriteRule version needs mod_rewrite; if your host only allows mod_alias, pick the RedirectMatch version.
How do I redirect a URL with a query string?
Apache needs a RewriteCond on %{QUERY_STRING}, Nginx can compare $request_uri, Vercel uses a has condition and Cloudflare Redirect Rules can test http.request.uri.query. Cloudflare Bulk Redirects cannot match query strings at all. The tool writes the right form for each.
Should I keep or drop the query string?
Keep it in most cases: UTM parameters and click IDs then survive the redirect and campaigns stay attributed. Drop it when the old parameters are meaningless on the new site, such as ?id=42 on a page that now has a clean URL.
How many redirect hops does Google follow?
Google’s crawlers follow up to 10 hops; beyond that the URL is reported as a redirect error. Fewer is better for users and crawl efficiency, which is why the tool flattens chains.
Is my URL list uploaded?
No. Everything is generated in your browser. Nothing is sent to TapCub and the tool has no share link.
Update history
New features, fixes and data refreshes for this tool, newest first.
-
· v1.0
LaunchedFirst release.
Missing something or found an error? Tell us — requests that come up often go into the next update. All tool updates
Finish the migration
Update the sitemap with the new URLs, keep hreflang pointing at final addresses, and make sure tracking links survive.