# Website migration SEO: how to move your site without losing traffic

> Move a website to a new host, CMS or domain without losing search traffic: benchmark, map every URL, test redirects, run the cutover and monitor the move.

- URL: https://computese.com/website-migration-seo/
- Author: Duong Quan Nguyen, CEO, Computese
- Published: 2026-09-28
- Updated: 2026-10-09
- Topics: Web development, SEO

## In short
- A migration keeps its search traffic when every old URL with traffic or links redirects permanently, in one hop, to an equivalent new page, and the new pages carry equivalent content, titles, canonicals and structured data.
- Use server-side 301 or 308 redirects and keep them for at least a year: Google treats a permanent redirect as a strong signal that the target should become canonical, and says permanent redirects do not cause a loss in PageRank.
- Change one thing at a time (domain, platform, design), launch into a traffic dip, and expect a medium-sized site to take a few weeks or more before the new URLs replace the old ones in Google.
- For a hosting move, lower the DNS TTL at least a week ahead, keep the old server running until its logs show zero traffic, and only then shut it down.
- Test the whole redirect map with a script before and after launch; the classic failures are leftover noindex rules, chains, loops, and redirects to pages that do not exist.

A website migration keeps its search traffic when every old URL that earns visits or links redirects permanently, in one hop, to its new equivalent, when the new pages carry the same content, titles and structured data, and when Search Console is watched for weeks after launch.

That is the short version. The long version below covers the four moves behind nearly every migration brief: changing hosts, switching HTTP to HTTPS, replatforming to a new CMS (with or without new URLs) and changing domains. It is written for the owner, marketer or developer who has to run one, and it stays practical: the redirect rules, the DNS steps, the test script and the monitoring routine. If the rebuild is a move to a headless architecture, the [headless CMS guide](https://computese.com/headless-cms/) covers the platform questions; this post covers keeping the search side intact. For how sites are built, launched and maintained in the first place, the [web development guide](https://computese.com/web-development-guide/) is the companion.

## Pick the migration you are actually doing

"Website migration" covers several different jobs with very different risk. Google itself splits the work into two guides: [moves with URL changes](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes) (domain, protocol, paths, merges) and [hosting moves without URL changes](https://developers.google.com/search/docs/crawling-indexing/site-move-no-url-changes). Start by naming yours:

| Migration                       | URLs change     | Main search risk                           | The rule that matters most                        |
| ------------------------------- | --------------- | ------------------------------------------ | ------------------------------------------------- |
| Hosting or CDN change           | No              | Downtime and slow responses during cutover | Keep both hosts live until the old one goes quiet |
| HTTP to HTTPS                   | Yes, the scheme | Mixed signals and certificate mistakes     | Permanent redirects plus a valid certificate      |
| Replatforming, URLs kept        | No              | Content, metadata and rendering drift      | A parity diff of old and new before launch        |
| Replatforming with new URLs     | Yes             | Unmapped URLs and redirect chains          | A complete, tested redirect map                   |
| Domain change                   | Yes             | Signals split between two domains          | Redirects plus the Change of Address tool         |
| Redesign with rewritten content | Partly          | Google must relearn the pages              | Do not combine it with a domain move              |
| Merging two sites               | Yes             | Confused consolidation                     | Move one site at a time                           |

The risk column is judgment, not a Google rating; the rules on the right come from the sources linked below.

Two planning rules pay for themselves before anything technical starts:

1. **Change one thing at a time.** Google's own example: if you want a new domain, a new CMS and a new layout, move the domain first, then change the layout, as separate steps. A migration that changes everything at once makes every later symptom ambiguous.
2. **Launch into a traffic dip.** If traffic dips on weekends or in a season, move then: fewer people hit any problem, and more of the server's capacity is free for the crawler that is about to recheck everything.

Expect a visible dip anyway. Google says ranking fluctuation during a move is normal: a medium-sized site can take a few weeks or more before the new URLs replace the old ones in results, longer for large sites, because the move is processed URL by URL. The move is done when the crawler has visited every old and new URL at least once, not when the last redirect goes in. For the mechanics behind that, [how the Google search engine works](https://computese.com/how-google-search-engine-works/) is the short version.

## Benchmark the site before you change anything

A migration without a benchmark cannot be verified. You need a "before" picture of what earned traffic and links, so that every later wobble can be compared against it. Capture five things:

1. **Search Console performance data.** Export the queries and pages tables for the full window. Google's [traffic-drop debugging guide](https://developers.google.com/search/docs/monitor-debug/debugging-search-traffic-drops) works with the "Last 16 months" date filter, and suggests the Search Analytics API or bulk data exports to keep more. The UI export tops out at 1,000 rows, according to Google's [2022 post on performance data filtering and limits](https://developers.google.com/search/blog/2022/10/performance-data-deep-dive); for a bigger site, the Search Analytics API returns up to 25,000 rows per request (page through them with `startRow`), within a cap of 50,000 rows per day per site per search type. If you want history older than 16 months later, [start a bulk data export](https://support.google.com/webmasters/answer/12917675) now: its first export covers the day of the export, and Google points to the API or the reports for data that precedes the setup.
2. **The [Links report](https://support.google.com/webmasters/answer/9049606).** Save the top linked pages and the list of linking sites; you will ask the valuable ones to update after the move. The report is a sample rather than a complete list: its tables are limited to 1,000 rows, and the export goes up to 100,000 rows.
3. **Analytics.** Organic landing pages by sessions and conversions for at least the last year, so the seasonal shape is visible.
4. **A full crawl of the old site.** Google's guide points readers at Screaming Frog's migration guide; any crawler that exports status codes, titles, canonicals and links works. Cross-check with server logs for URLs visited at least once recently, and include embedded content: images, videos, JavaScript and CSS files are URLs that move too.
5. **A restore-tested backup** of files and database. Migrations are exactly the day a backup earns its keep; [what to copy and how to test a restore](https://computese.com/the-importance-of-backup-solutions-for-website/) is a checklist of its own.

## Build the redirect map

The redirect map is the deliverable the migration stands on: one row per old URL, with its decision.

Inventory first. Google lists the sources: the XML sitemaps, the CMS's list of content URLs, server logs or analytics for the URLs with traffic, and the Links report for URLs with external links. Pick a log window that covers your seasonal variation. Every URL found becomes a row.

![Two site maps of document cards with arrows from each old page to its new page, and one old page whose arrow is missing, circled with a dashed line.](https://computese.com/images/blog/website-migration-seo/url-map.cacdb6b445-1536.webp)

*Every old URL needs exactly one decision; the page nobody listed is the one that loses its traffic.*

Then decide. Each old URL gets one of four outcomes:

- **Keep.** The URL still fits; its content, title, canonical and structured data must match or improve.
- **Redirect, one to one.** The content moved; a permanent redirect to the single equivalent page.
- **Merge.** Several thin or competing pages become one stronger page, and all the old URLs redirect to it.
- **Retire.** No successor worth sending anyone to; the URL returns 404 or 410.

The status codes, from [RFC 9110](https://www.rfc-editor.org/rfc/rfc9110.html) and [Google's redirect documentation](https://developers.google.com/search/docs/crawling-indexing/301-redirects):

- **301 Moved Permanently and 308 Permanent Redirect** both say the resource has a new permanent URI. The difference is in the client: for historical reasons, RFC 9110 lets a user agent change a POST into a GET after a 301 or 302, and it points to 308 (or 307 for a temporary move) when that is unwanted. For search, [Google's crawler documentation](https://developers.google.com/crawling/docs/troubleshooting/http-status-codes) calls 308 equivalent to 301, and the redirects guide says Google uses a permanent redirect as a signal that the target should be canonical; the site move guide adds that permanent redirects do not cause a loss in PageRank. A 301 is the conservative default: RFC 9110 notes that 308 is much younger (June 2014) and might not be recognized everywhere, and [nginx](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html) did not treat 308 as a redirect until version 1.13.0.
- **302 Found and 307 Temporary Redirect** are for moves you will revert. Google keeps showing the source page in results (its crawler documentation calls a 302 only a weak signal that the target should be processed), and [Bing's guidelines](https://www.bing.com/webmasters/help/webmaster-guidelines-30fba23a) reserve 302 for very short-term changes, less than two days.

Server-side beats browser-side. Google recommends server-side redirects wherever possible; an instant meta refresh counts as permanent and a delayed one as temporary, and JavaScript redirects are the documented last resort, because rendering can fail and Google might never see the redirect. On Apache that means configuration or `.htaccess` rules; on a CMS, the platform's own redirect function.

One hop, not chains. Google's crawlers follow up to ten redirect hops, per the same crawler documentation, but the site move guide advises redirecting to the final destination directly and, when that is not possible, keeping the chain short: ideally no more than three hops and fewer than five. Chains add latency for users, and not all user agents and browsers support long ones. Migrations breed chains by accident (old URL, slash variant, new section, final page), so collapse them inside the map.

![A browser reaching a document two ways: a zigzag path through two intermediate servers, and one direct arrow below that skips them.](https://computese.com/images/blog/website-migration-seo/redirect-chain.76075137c2-1536.webp)

*A chain still arrives, but every extra hop costs latency and crawl effort; point each old URL straight at the final page.*

Do not mass-redirect to the home page. Google warns that redirecting many old URLs to one irrelevant destination, such as the new home page, can confuse users and might be treated as a soft 404. The exception it names is consolidated content: pages merged into one can all redirect to the merged page.

> [!WARNING]
> Do not send a whole section to the home page; Google may treat that as a soft 404. Map every kept page to its real equivalent, and let retired pages answer honestly with 404 or 410.

Retirement deserves the same care as redirection. RFC 9110 defines 410 Gone as access to the resource being no longer available, a condition likely to be permanent, and says 404 is the right code when the server cannot tell. Google's crawler documentation adds that it does not index URLs that return a 4xx and removes already indexed ones, and Bing's guidelines ask for a 404 on permanently removed content. The [Page indexing report](https://support.google.com/webmasters/answer/7440203) is blunt about the tail: there is no way to tell Googlebot to forget a URL permanently, so it keeps trying a 404 for some time while crawling it less and less often. That is why a correct status code matters more than hoping the old URL fades.

Store the map as data, not as a pile of handwritten rules: a two-column CSV that every platform in the platform section below can be generated from.

```csv
old_url,expected
https://www.example.com/services/web-design/,https://www.example.com/services/web-design-development/
https://www.example.com/promo-2022/,410
https://www.example.com/blog/2019/05/widgets,https://www.example.com/blog/widgets/
```

## Match content, metadata and signals

Redirects carry the old URLs' signals; parity is what keeps the new pages worthy of them. Check the new site against the old, page for page:

- **Primary content** answers the same query as the page it replaces. A merged page must serve both of the pages it absorbs.
- **Title and meta description** carry over unless the change is deliberate.
- **Canonicals**: every new URL gets a self-referencing `rel="canonical"` with an absolute URL; the [canonicalization guide](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls) prefers absolute paths because relative ones can cause problems in the long run. In the same guide, redirects and `rel="canonical"` are strong signals, sitemap inclusion is a weak one, and the methods stack when combined.
- **Hreflang**, if the site is multilingual: update every annotation to the new URLs. Google's [localized versions guide](https://developers.google.com/search/docs/specialty/international/localized-versions) says each language version must list itself and all the others, with fully-qualified URLs, and that annotations without return links may be ignored.
- **Structured data** carries over to the equivalent pages, verified on staging rather than in production.
- **Internal links** point at the final new URLs, never at URLs that redirect. Updating internal links is its own item on Google's checklist, and the pragmatic reason is simple: redirects are slow for users, and each hop is another crawl request.
- **A new XML sitemap** of the new URLs, built and ready to submit. Per Google's [sitemap documentation](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap), one sitemap file holds at most 50,000 URLs and 50MB uncompressed; larger sites split it and submit a sitemap index.

## Stage and test the new site

Protect staging with a password or an IP allowlist, not robots.txt. Google's hosting guide suggests an IP-restricted testing environment, or a temporary hostname with `noindex` in the HTML or HTTP headers. The [introduction to robots.txt](https://developers.google.com/search/docs/crawling-indexing/robots/intro) states plainly that robots.txt is not a mechanism for keeping a page out of Google: a disallowed URL can still be indexed from links elsewhere, and the way to keep a page out is `noindex` or a password. Combining robots.txt with `noindex` defeats the purpose: per Google's [noindex documentation](https://developers.google.com/search/docs/crawling-indexing/block-indexing), the crawler never sees a `noindex` rule on a page that robots.txt blocks.

Then test, in this order:

1. **Crawl staging and diff it against the old crawl**: titles, descriptions, canonicals, structured data, status codes. Every difference is a decision that someone should be able to explain. This is a [technical SEO audit](https://computese.com/technical-seo/) scoped to a single release.
2. **Measure performance before launch.** A rebuild is the easiest place to regress page experience, and the time to catch it is while the old site still serves; the [Core Web Vitals guide](https://computese.com/core-web-vitals/) covers the thresholds and how to measure them.
3. **Test the redirect map against the new server before DNS moves.** [`curl --resolve`](https://curl.se/docs/manpage.html) supplies a custom address for a host and port pair, much like an `/etc/hosts` entry on the command line, so the production URLs can be tested against the new host while the world still sees the old one:

```bash
curl -s -o /dev/null -w '%{http_code} %{redirect_url}\n' \
  --resolve www.example.com:443:203.0.113.10 \
  https://www.example.com/services/web-design/
```

(The address is a placeholder; use your new host's. The status and redirect target it prints are exactly what the launch-day script checks for the whole map.)

4. **Get the certificate in place.** The new host needs a valid certificate covering every host variant (the bare domain and `www` at minimum) before the cutover: Google's canonicalization guide warns that bad TLS certificates and HTTPS-to-HTTP redirects make it prefer the HTTP version very strongly. With Let's Encrypt, the [HTTP-01 challenge](https://letsencrypt.org/docs/challenge-types/) puts a file on the web server behind the domain's own address on port 80, which mid-migration still points at the old server; the DNS-01 challenge proves control with a TXT record instead, so the certificate can be issued before DNS changes. [Renewing and installing certificates](https://computese.com/ssl-certificate/) is covered step by step in its own guide.
5. **Check robots.txt on the new site** with fresh eyes. If the file does not exist, the server must answer 404: Google's list of common migration mistakes asks for a proper 404, and its [robots.txt specification](https://developers.google.com/crawling/docs/robots-txt/robots-txt-spec) treats any 4xx other than 429 as no crawl restrictions. A 5xx is the dangerous answer: per that specification, Google stops crawling the site for the first 12 hours while it keeps trying to fetch the file.

## Plan the DNS cutover

For a hosting move, the cutover is a DNS change, and its one control knob is the TTL. [RFC 1035](https://www.rfc-editor.org/rfc/rfc1035.html) defines the TTL as the time interval, in seconds, that a record may be cached before it should be discarded. It also describes TTLs of cached data as counting down while the data in the zone keeps a constant TTL, which is why the same question gets two different answers:

```bash
$ dig +noall +answer shop.example.com          # your caching resolver
shop.example.com.	241	IN	A	203.0.113.10

$ dig +noall +answer shop.example.com @ns1.provider.example   # the authoritative server
shop.example.com.	300	IN	A	203.0.113.10
```

(Illustrative output with a placeholder host name; the pattern comes from real `dig` runs. 241 is the seconds the resolver's cache has left, 300 the configured TTL.)

[RFC 2181](https://www.rfc-editor.org/rfc/rfc2181.html) pins the semantics down: a TTL is a maximum time to live, not a mandatory one. So plan for the worst case: a resolver that cached the record one second before your change may serve the old address for the entire previous TTL. You cannot flush the world's caches; you can only shrink the number ahead of time. Google's hosting guide tells you how: consider lowering the TTL to a conservative low value, for example a few hours, at least a week before the move.

![A DNS record card joined by a line to a small round clock; an arrow from the clock passes a faint dashed server, the old host, and ends at a solid server, the new host.](https://computese.com/images/blog/website-migration-seo/dns-ttl.8bc4c4996c-1536.webp)

*A resolver that cached the record just before the change can serve the old answer for the whole previous TTL, so the TTL comes down a week before the move.*

Create new records early, too. Negative answers cache as well: [RFC 2308](https://www.rfc-editor.org/rfc/rfc2308.html) lets a resolver remember that a name does not exist, for a TTL derived from the zone's SOA record, which is why a record added at the last minute can look broken to some users right after you add it.

The cutover itself:

1. **A week out**, lower the TTL on every record that will change.
2. **Deploy and test** the site on the new host (the previous section), and if the move is part of a bigger infrastructure program, the [cloud migration strategy guide](https://computese.com/cloud-migration-strategy/) covers the sequencing of the rest.
3. **T minus zero**: update the A, AAAA or CNAME records.
4. **Watch propagation** with public resolvers (`dig @1.1.1.1`, or any public DNS checker) and with the server logs on both hosts: the old one declines as the new one grows.
5. **Expect a crawl-rate wobble**: Google describes a temporary drop in Googlebot's crawl rate right after a hosting change, followed by a steady increase over the next few days.
6. **Shut the old host down only when its logs show zero traffic.** Until then it is the rollback: point DNS back and the move is undone. That is how our [hosting and maintenance](https://computese.com/services/hosting-maintenance/) service runs a host move: rehearsed on a staging address, cut over with lowered TTLs, and the previous host kept warm as the rollback.

If the domain itself is changing, DNS is the small part. The old domain must keep answering, because the redirects live there: the [Change of Address help page](https://support.google.com/webmasters/answer/9370220) suggests continuing to pay for the old domain for at least a year, and both domains stay verified in Search Console.

## Launch day, in order

Launch day is a fixed sequence: the blocks come off first, the switch flips second, and the checks run before anyone declares the move done.

1. **Remove the safety blocks.** The first item on Google's list of common migration mistakes is `noindex` rules or robots.txt blocks that were only needed for the migration. Check the live HTML and fetch `/robots.txt` yourself.
2. **Flip the switch**: the DNS change for a hosting move, or the redirect rules for URL and domain moves. Google recommends small and medium-sized sites move all URLs at once; a large site can go section by section, starting with a section that changes infrequently.
3. **Confirm the certificate** and HTTPS on every live hostname variant.
4. **Test the whole redirect map with a script.** This one checks each old URL for a permanent status and a direct hit on the expected target, using curl's `http_code`, `redirect_url`, `num_redirects` and `url_effective` write-out variables:

```bash
#!/usr/bin/env bash
# Usage: ./check-redirects.sh map.csv
# map.csv rows: old_url,expected (expected is the final URL, or a status like 410)
fetch() { local fmt=$1; shift; curl -s -o /dev/null -w "$fmt" "$@"; }

bad=0
while IFS=, read -r old expected; do
  expected=${expected%$'\r'}
  [[ -z $old ]] && continue
  read -r code target < <(fetch '%{http_code} %{redirect_url}' "$old")
  if [[ $expected =~ ^[0-9]{3}$ ]]; then
    [[ $code == "$expected" ]] && result=OK || result="WANT-$expected"
  elif [[ $code != 301 && $code != 308 ]]; then
    result=NOT-PERMANENT
  elif [[ $target != "$expected" ]]; then
    read -r hops final < <(fetch '%{num_redirects} %{url_effective}' -L --max-redirs 10 "$old")
    [[ $final == "$expected" ]] && result="CHAIN-$hops-HOPS" || result=WRONG-TARGET
  elif [[ $(fetch '%{http_code}' "$expected") != 200 ]]; then
    result=TARGET-NOT-200
  else
    result=OK
  fi
  [[ $result == OK ]] || bad=1
  printf '%-16s %s  %s\n' "$result" "$code" "$old"
done < "$1"
exit "$bad"
```

Its output against a deliberately flawed map, from a run against a local test server with its address replaced by example.com:

```text
OK               301  https://example.com/services/web-design/
OK               410  https://example.com/promo-2022/
CHAIN-2-HOPS     301  https://example.com/blog/2019/05/widgets
NOT-PERMANENT    302  https://example.com/pricing/
WRONG-TARGET     301  https://example.com/case-studies/acme/
TARGET-NOT-200   301  https://example.com/products/blue-widget/
WANT-410         404  https://example.com/old-news/
OK               308  https://example.com/team/
```

Every non-OK row names its failure: a chain to collapse, a 302 to make permanent, a wrong or broken target, a retired page returning the wrong status. The script exits 1 when anything fails, so it can gate a deployment.

5. **Spot-check the money URLs** in Search Console's [URL Inspection tool](https://support.google.com/webmasters/answer/9012289); Google's guide suggests it for individual URLs, with command line tools or scripts for large numbers of them.
6. **Submit the sitemap of new URLs**, and keep the old-URL sitemap submitted as well: Google's monitoring advice is to submit both, so the indexed counts drain from one and fill the other, and it says the warnings about redirecting URLs in the old sitemap are normal.
7. **Domain change only: submit the [Change of Address](https://support.google.com/webmasters/answer/9370220)** for the old property, after the redirects are live. The requirements: you own both properties and manage them with the same Google account, and you work at the domain level (example.com, not example.com/shop); the tool moves all protocols but no subdomains, so submit a request for every verified subdomain variant, www and non-www included, even ones you no longer use. It is not for HTTP to HTTPS, www versus non-www, or path-only moves. It runs pre-move checks (including for 301s), keeps its notifications up for 180 days, and can be cancelled within that window. Two more rules from the same page: do not chain moves (after a request from A to B you cannot immediately submit B to C), and avoid moving several sites into one location at the same time.
8. **Tell Bing.** Bing once had a Site Move tool in Webmaster Tools, and a [2020 guest post on the Bing Webmaster Blog](https://blogs.bing.com/webmaster/2020/12/Website-Migration-with-Bing/) still tells readers to use it. The help page that post links to returns a 404 as of 9 October 2026, and the current [Bing Webmaster Guidelines](https://www.bing.com/webmasters/help/webmaster-guidelines-30fba23a) describe no such tool. They ask instead for 301 redirects on permanent moves, sitemaps that list only canonical URLs with redirected URLs removed promptly, and [IndexNow](https://www.indexnow.org/documentation) notifications for URLs that are added, updated or removed. IndexNow takes up to 10,000 URLs per POST behind a key file hosted on your domain, and an HTTP 200 response means only that the search engine has received the URLs; Bing's guidelines prefer streaming submissions to batches where possible.
9. **Housekeeping.** Re-upload any disavow file on the new property, as Google recommends, and confirm the Search Console verification file or meta tag survived the move.
10. **Update what you control**: social profiles, ad landing pages, and the highest-traffic sites linking in from the benchmark's list. Redirects carry the rest.

## Watch the first twelve weeks

**Week 1: errors before rankings.** Read the [Page indexing report](https://support.google.com/webmasters/answer/7440203) daily. The statuses that matter now are "Redirect error" (a chain that was too long, a loop, a bad or empty URL), "Soft 404", "Not found (404)", "URL marked 'noindex'" and "URL blocked by robots.txt". Old URLs should drift into "Page with redirect", which is not an error: redirect URLs are not indexed, only the redirect target. Export the 404 list early, because it only covers URLs that returned 404 in the past month. When a fix ships, use "Validate fix"; validation typically takes up to about two weeks, and can take much longer. In the [Crawl Stats report](https://support.google.com/webmasters/answer/9679690) (root-level properties only, and Google says sites with fewer than a thousand pages will not need it), watch host status: robots.txt availability, DNS resolution and host connectivity. Note that each hop of a redirect chain is counted there as a separate request, so chains inflate crawl load exactly when Google is crawling the new site hardest. Keep tailing both servers' logs. For the mechanics behind these reports, [web crawling and indexing, explained](https://computese.com/web-crawling-and-indexing-explained/) covers the pipeline.

> [!TIP]
> Export the 404 list in week 1 and weekly after that. It only ever shows the past month, so the record of what broke ages out while you are fixing it.

**Month 1: compare against the benchmark.** Impressions and clicks for the exported pages and queries, old property draining while the new one fills. Fluctuation is expected; what matters is the shape: a new URL that stays at zero while its old twin also reads zero is probably a page Google has not recrawled yet, and URL Inspection will show what Google last saw.

**Months 2 to 3: settle the tail.** A medium site should have most URLs moved; large sites take longer. Old URLs occasionally appearing in results is normal: Google keeps the old URL as an "alternate name" of the canonical for a while, and it fades without intervention. Keep the redirects up for as long as possible, at least a year by the site move guide (the Change of Address page's floor is 180 days, longer if they still get traffic; the 2020 Bing Webmaster Blog guest post suggests one to two years or more), and keep the old domain registered for at least a year. Ask the top linking sites to update their links: redirects are slow for users, and every updated link is one less dependency on the redirect layer.

We ran this site's own move off WordPress by the same rules (blog URLs unchanged, every other change a recorded decision). The same URL map, pre-launch verification and post-launch monitoring are what our [SEO service](https://computese.com/services/seo/) and [web design and development](https://computese.com/services/web-design-development/) service apply to a launch.

## Redirect rules on your platform

Wherever the rules live, prefer a layer that answers before the CMS or application code runs (the web server, the CDN or the framework's routing): a redirect that never reaches the CMS cannot fail with it.

### WordPress

Rewrite URLs inside content with WP-CLI rather than raw SQL: [`wp search-replace`](https://developer.wordpress.org/cli/commands/search-replace/) handles PHP serialized data and supports `--dry-run`, while the WordPress handbook warns that a plain search and replace over the whole database can break serialized values that some themes and widgets store. The [Migrating WordPress](https://developer.wordpress.org/advanced-administration/upgrade/migrating/) guide adds two blunt rules: never change the `guid` column (feed readers use it to recognize posts they have already seen), and back up `.htaccess` before touching it, which it calls a requirement, not a recommendation.

```bash
wp search-replace 'https://old.example.com' 'https://www.example.com' --dry-run
wp search-replace 'https://old.example.com' 'https://www.example.com' --skip-columns=guid
```

Run separate passes for scheme and host variants, re-check the two address fields in Settings, then regenerate and review the permalinks. One more launch check: the Settings, Reading, "Discourage search engines from indexing this site" box makes WordPress output a `noindex, nofollow` meta tag since version 5.3, [per its documentation](https://wordpress.org/documentation/article/settings-reading-screen/); make sure it is unchecked before launch. Redirects themselves can live in a plugin or in server rules. A plugin keeps the map editable in the admin but runs only after PHP and WordPress have loaded; rules in `.htaccess` or the web server answer before WordPress starts and keep working if the plugin is switched off. The settings beyond the move are in the [WordPress SEO checklist](https://computese.com/wordpress-seo/).

### Shopify

Shopify's built-in [URL redirects](https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect) (with CSV import and export) come with hard edges, as of October 2026: a redirect only works from a URL that currently returns 404; the prefixes `/apps`, `/application`, `/cart`, `/carts`, `/orders`, `/services` and `/shop` cannot be redirected, and neither can the fixed paths `/products`, `/collections` and `/collections/all`; the cap is 100,000 redirects (20 million on Plus), and for a large number the page itself suggests a third-party app; URLs with query strings may not work as expected; and the page is not consistent about market subfolders (one section says a redirect applies to all of them, another says it does not apply automatically and that redirecting specific locales needs a redirect per subfolder), so test each market. Two consequences: retire or rename the old page before creating its redirect, and accept that `/products` and `/collections` are fixed paths, so a move onto Shopify means mapping every old product and collection URL onto them. Shopify also warns that browsers and search engines cache 301s, so a removed redirect can keep working from cache until it expires. The rest of the platform's search surface is in the [Shopify SEO checklist](https://computese.com/shopify-seo/), and product and filter URLs more broadly are in the [e-commerce SEO guide](https://computese.com/e-commerce-seo/).

### Next.js

Redirects live in `next.config`: `permanent: true` returns a 308 and `permanent: false` a 307 (Next.js uses those codes explicitly to preserve the request method), and `statusCode` can replace `permanent` when a specific code is needed. [The redirects reference](https://nextjs.org/docs/app/api-reference/config/next-config-js/redirects) notes they are checked before the filesystem, query strings pass through to the destination, and sources support wildcards and regex parameters:

```ts
// next.config.ts
import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  trailingSlash: true, // /about redirects to /about/
  async redirects() {
    return [
      {
        source: "/services/web-design",
        destination: "/services/web-design-development/",
        statusCode: 301,
      },
      {
        // Dated URLs collapse to flat slugs: /2021/05/12/my-post -> /my-post/
        source: "/:year(\\d{4})/:month(\\d{2})/:day(\\d{2})/:slug",
        destination: "/:slug/",
        statusCode: 301,
      },
    ];
  },
};

export default nextConfig;
```

With [`trailingSlash: true`](https://nextjs.org/docs/app/api-reference/config/next-config-js/trailingSlash), a request for the slashless URL redirects to the slashed one (files with extensions and paths under `.well-known/` are exempt), so write destinations with the trailing slash or every mapped URL earns a second hop. Platform caps apply: the Next.js [redirecting guide](https://nextjs.org/docs/app/guides/redirecting) notes that redirects may have platform limits, for example 1,024 on Vercel, and suggests a custom solution in Proxy once a map reaches 1,000 or more. This site's own redirect map uses the same regex rule to flatten dated blog URLs, with `trailingSlash` on and 301 status codes throughout.

### nginx

One map, one `return`. The [map module](https://nginx.org/en/docs/http/ngx_http_map_module.html) builds a lookup from [`$uri`](https://nginx.org/en/docs/http/ngx_http_core_module.html), which nginx defines as the current URI, normalized, as opposed to `$request_uri`, the full original URI with arguments. String keys in a map are matched ignoring case, and a map variable is evaluated only when it is used:

```nginx
# http block: the map lives in its own file, one pair per line
map $uri $new_url {
    default "";
    include /etc/nginx/redirect-map.conf;
}

server {
    listen 443 ssl;
    server_name old.example.com www.old.example.com;

    if ($new_url) {
        return 301 https://www.example.com$new_url;
    }

    # ... the rest of the old-site server config
}
```

```nginx
# /etc/nginx/redirect-map.conf
/services/web-design/ /services/web-design-development/;
/blog/2019/05/widgets /blog/widgets/;
/team/ /about/team/;
```

`return` with a URL supports 301, 302, 303, 307 and, from nginx 1.13.0, 308. A map with thousands of entries may need `map_hash_max_size` raised past its 2048 default; `nginx -t` will tell you before a reload does. (Configuration verified against the nginx documentation; test on your own staging before trusting it.)

### Apache

Start with [mod_alias](https://httpd.apache.org/docs/2.4/mod/mod_alias.html): Apache's own guide to [when not to use mod_rewrite](https://httpd.apache.org/docs/2.4/rewrite/avoid.html) calls it a last resort, for when the alternatives fall short. `RedirectMatch` takes a regular expression, so `^` and `$` pin an exact path, while plain `Redirect` is a prefix match that appends the remainder of the path (right for whole trees, wrong for single pages), and the `gone` status returns a 410 with no target. mod_alias is built for simple URL manipulation, and Apache's documentation sends tasks such as manipulating the query string to mod_rewrite, so a URL identified by its query string needs a `RewriteCond`:

```apache
# One-to-one moves (mod_alias)
RedirectMatch permanent "^/services/web-design/?$" "https://www.example.com/services/web-design-development/"

# Retired for good: 410, no target
RedirectMatch gone "^/promo-2022(/.*)?$"

# An old URL identified by its query string (mod_rewrite)
RewriteEngine On
RewriteCond %{QUERY_STRING} ^id=42$
RewriteRule ^/product\.php$ "https://www.example.com/products/blue-widget/?" [R=301,L]
```

The [mod_rewrite reference](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html) says to end the substitution with just a question mark to erase the old query string; without it, a redirect to an absolute URL carries the requested query string along. The [RewriteRule flags](https://httpd.apache.org/docs/2.4/rewrite/flags.html) page confirms that `[R]` without a code means 302, so write `[R=301,L]`. In an `.htaccess` file (per-directory context) the pattern matches the path without its leading slash: `^product\.php$`. This configuration passed `httpd -t` on Apache 2.4.67, which checks the syntax, not the behaviour; test it on staging.

## Symptom, cause, fix

The week after launch, these are the failures that actually show up, mapped to their fixes:

| Symptom                                              | Likely cause                                                           | Fix                                                                                               |
| ---------------------------------------------------- | ---------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
| New pages absent; report says "URL marked 'noindex'" | Staging noindex, or the CMS "discourage" option, shipped to production | Remove it, then request indexing on the key URLs                                                  |
| "URL blocked by robots.txt" across the site          | Staging robots.txt copied to production                                | Restore the real robots.txt; a missing file must return 404, and a 5xx stops crawling             |
| "Redirect error" entries climbing                    | Chains too long, loops, or empty targets                               | Point every rule at the final URL and re-run the map script                                       |
| "Soft 404" across whole sections                     | Mass redirect to the home page or another irrelevant page              | Map to real equivalents, or return 404/410                                                        |
| "Not found (404)" keeps growing                      | URLs nobody mapped                                                     | Mine the report and the server logs, add the missing rules; Google retries old URLs for some time |
| Crawl Stats host status red, crawl rate falling      | New server overloaded, or a firewall blocking Googlebot                | Add capacity and let Googlebot through; Google crawls the new site more heavily for a while       |
| Traffic down, indexing clean                         | Content changed with the URLs, so Google is relearning the pages       | Expected when a redesign rides along with a move; compare per page against the benchmark          |
| Old URLs still appear in results weeks later         | Nothing broken: the old URL lingers as an alternate name               | No action; it fades                                                                               |

## The website migration checklist

Two weeks out:

1. Benchmarks exported: 16 months of performance data, the Links report, analytics, and the bulk export enabled.
2. Full crawl and log-based URL inventory, assets included.
3. Redirect map finished: one decision per URL, no chains, no mass redirects.
4. Backup of files and database, restore-tested.

Before launch:

1. New site on staging behind authentication, crawled and diffed against the old crawl.
2. Canonicals self-referencing, hreflang updated, structured data carried over, internal links rewritten to final URLs.
3. New XML sitemap built; robots.txt reviewed; every noindex and crawl block listed for removal.
4. Certificate valid on the new host for every hostname variant (DNS-01 lets you issue it before the cutover).
5. Performance of the new build measured, not assumed.
6. Redirect map tested on the new server with the script, zero non-OK rows.
7. TTL lowered; old host committed to stay up; Search Console verified for every property variant, old and new.

Launch day:

1. noindex off, crawl blocks removed, robots.txt answering 200 or 404, never 5xx.
2. DNS updated, or redirects enabled.
3. Certificate and HTTPS confirmed on the live hostnames.
4. The map test re-run against production.
5. New sitemap submitted, old-URL sitemap kept, disavow file re-uploaded.
6. Change of Address submitted for every verified variant (domain moves only).
7. IndexNow notification sent for the new URLs.
8. Profiles, ads and top referrers updated.

After launch:

1. Week 1: Page indexing and Crawl Stats read daily, both servers' logs watched, fixes validated.
2. Month 1: rankings and clicks compared per page against the benchmark.
3. Months 2 to 3: top linking sites asked to update, the 404 list mined weekly.
4. Long term: redirects stay at least a year and the old domain stays registered at least a year; the old host goes only once its logs read zero.

## Key terms
- **301 redirect**: The permanent redirect status code: the resource has been assigned a new permanent URI. Google reads it as a strong signal that the redirect target should become canonical.
- **308 redirect**: The permanent redirect added in June 2014. RFC 9110 points to it when a 301's habit of turning a POST into a GET is unwanted; Google treats 308 and 301 as equivalent.
- **302 redirect**: A temporary redirect: Google shows the source page in results, not the target. Bing's guidelines reserve 302 for very short-term changes, less than two days.
- **Redirect chain**: An old URL that redirects to another redirect. Googlebot follows up to ten hops, but every hop adds latency and a failure mode, so the map should point straight at the final URL.
- **Soft 404**: A page that looks like an error but returns a success status instead of 404, or a redirect to an irrelevant page. Redirecting many old URLs to the home page can be treated as soft 404s.
- **410 Gone**: The status code for content that is no longer available and is likely to stay that way. RFC 9110 says to use 404 instead when the server cannot tell whether the removal is permanent.
- **DNS TTL**: Time to live: the time in seconds a DNS record may be cached before it should be discarded. Caches count it down; lowering it ahead of a move shortens the cutover's tail.
- **Change of Address tool**: A Search Console tool that tells Google a site moved to a new domain or subdomain. It works on domain-level properties only and does not cover HTTP to HTTPS or path-only moves.
- **Canonical URL**: The URL you want people to see in search results when several URLs show the same or very similar content. Redirects and rel=canonical annotations are strong signals for it; a sitemap entry is a weak one.

## Common questions

### How long does a website migration take to settle in Google?

Google's site move guide says a small to medium-sized website can take a few weeks for most pages to move, and larger sites take longer, because the move is processed URL by URL. The Change of Address tool keeps its migration notifications running for 180 days. Rankings can fluctuate during the move and then settle.

### Do 301 redirects hurt PageRank?

No. Google's site move guide states that 301 and other permanent redirects do not cause a loss in PageRank, and its redirect documentation reads a 301 or 308 as a signal that the redirect target should be canonical. The risk sits in missing, chained or broken redirects, not in the status code itself.

### How long should redirects stay in place after a migration?

Google advises keeping them as long as possible, generally at least one year, so links on other sites can be recrawled and reassigned to the new URLs. The Change of Address help page sets a floor of 180 days, longer if the redirects still get search traffic, and suggests keeping the old domain registered for at least a year.

### Can I use the Change of Address tool for an HTTP to HTTPS move?

No. The tool is only for moving from one domain or subdomain to another, and Google lists HTTP to HTTPS, www versus non-www, and path-only changes as moves it does not cover. For those it points to permanent redirects, canonical tags where they apply, and updated sitemaps.

### How do I move hosts without downtime?

Run both servers at once: lower the DNS TTL well in advance, update the record, then keep the old host serving until its logs show no traffic and only shut it down after that. Google's hosting change guide notes a temporary dip in Googlebot's crawl rate right after the switch, followed by a steady increase over the next few days.

### What is the most common reason a migration loses traffic?

Google's list of common mistakes leads with leftover noindex rules and robots.txt blocks, followed by redirects that point at non-existent URLs. Both are pre-launch failures: a staging protection that shipped to production, or a redirect map nobody tested against the live server.

### Does Bing have an equivalent of Google's Change of Address tool?

Not any more, as far as Bing's published pages show. A 2020 guest post on the Bing Webmaster Blog still names a Site Move tool, but the help page it links to returns a 404 as of 9 October 2026. The current guidelines ask for 301 redirects, sitemaps that list only canonical URLs, and IndexNow notifications for added, updated or removed URLs.

## Sources
1. [How to move a site](https://developers.google.com/search/docs/crawling-indexing/site-move-with-url-changes), Google Search Central
2. [Changing your hosting](https://developers.google.com/search/docs/crawling-indexing/site-move-no-url-changes), Google Search Central
3. [Redirects and Google Search](https://developers.google.com/search/docs/crawling-indexing/301-redirects), Google Search Central
4. [Change of Address tool](https://support.google.com/webmasters/answer/9370220), Google Search Console Help
5. [How HTTP Status Codes Affect Google's Crawlers](https://developers.google.com/crawling/docs/troubleshooting/http-status-codes), Google Crawling Infrastructure
6. [Debug Google Search Traffic Drops](https://developers.google.com/search/docs/monitor-debug/debugging-search-traffic-drops), Google Search Central
7. [Search Console performance data filtering and limits](https://developers.google.com/search/blog/2022/10/performance-data-deep-dive), Google Search Central Blog
8. [Start a new bulk data export](https://support.google.com/webmasters/answer/12917675), Google Search Console Help
9. [Links report](https://support.google.com/webmasters/answer/9049606), Google Search Console Help
10. [RFC 9110: HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110.html), IETF RFC Editor
11. [How to specify a canonical URL with rel="canonical" and other methods](https://developers.google.com/search/docs/crawling-indexing/consolidate-duplicate-urls), Google Search Central
12. [Localized Versions of your Pages](https://developers.google.com/search/docs/specialty/international/localized-versions), Google Search Central
13. [Build and Submit a Sitemap](https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap), Google Search Central
14. [Introduction to robots.txt](https://developers.google.com/search/docs/crawling-indexing/robots/intro), Google Search Central
15. [Block Search Indexing with noindex](https://developers.google.com/search/docs/crawling-indexing/block-indexing), Google Search Central
16. [How Google Interprets the robots.txt Specification](https://developers.google.com/crawling/docs/robots-txt/robots-txt-spec), Google Crawling Infrastructure
17. [curl - How To Use](https://curl.se/docs/manpage.html), curl
18. [Challenge Types](https://letsencrypt.org/docs/challenge-types/), Let's Encrypt
19. [RFC 1035: Domain Names, Implementation and Specification](https://www.rfc-editor.org/rfc/rfc1035.html), IETF RFC Editor
20. [RFC 2181: Clarifications to the DNS Specification](https://www.rfc-editor.org/rfc/rfc2181.html), IETF RFC Editor
21. [RFC 2308: Negative Caching of DNS Queries (DNS NCACHE)](https://www.rfc-editor.org/rfc/rfc2308.html), IETF RFC Editor
22. [Page indexing report](https://support.google.com/webmasters/answer/7440203), Google Search Console Help
23. [Crawl Stats report](https://support.google.com/webmasters/answer/9679690), Google Search Console Help
24. [URL Inspection tool](https://support.google.com/webmasters/answer/9012289), Google Search Console Help
25. [Bing Webmaster Guidelines](https://www.bing.com/webmasters/help/webmaster-guidelines-30fba23a), Bing Webmaster Tools
26. [Website Migration with Bing](https://blogs.bing.com/webmaster/2020/12/Website-Migration-with-Bing/), Bing Webmaster Blog
27. [IndexNow Documentation](https://www.indexnow.org/documentation), IndexNow
28. [wp search-replace](https://developer.wordpress.org/cli/commands/search-replace/), WP-CLI, WordPress Developer Resources
29. [Migrating WordPress](https://developer.wordpress.org/advanced-administration/upgrade/migrating/), WordPress Developer Resources
30. [Settings Reading screen](https://wordpress.org/documentation/article/settings-reading-screen/), WordPress.org Documentation
31. [Creating and managing URL redirects](https://help.shopify.com/en/manual/online-store/menus-and-links/url-redirect), Shopify Help Center
32. [next.config.js: redirects](https://nextjs.org/docs/app/api-reference/config/next-config-js/redirects), Next.js
33. [next.config.js: trailingSlash](https://nextjs.org/docs/app/api-reference/config/next-config-js/trailingSlash), Next.js
34. [Guides: Redirecting](https://nextjs.org/docs/app/guides/redirecting), Next.js
35. [Module ngx_http_map_module](https://nginx.org/en/docs/http/ngx_http_map_module.html), nginx
36. [Module ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html), nginx
37. [Module ngx_http_rewrite_module](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html), nginx
38. [mod_alias](https://httpd.apache.org/docs/2.4/mod/mod_alias.html), Apache HTTP Server Project
39. [When not to use mod_rewrite](https://httpd.apache.org/docs/2.4/rewrite/avoid.html), Apache HTTP Server Project
40. [mod_rewrite](https://httpd.apache.org/docs/2.4/mod/mod_rewrite.html), Apache HTTP Server Project
41. [RewriteRule Flags](https://httpd.apache.org/docs/2.4/rewrite/flags.html), Apache HTTP Server Project
