Moving a website is not one job but four, and which one you are doing determines the entire risk profile: changing servers alone (a hosting move) is close to risk-free, while changing the domain or the URL structure puts all of your search traffic on the line. The rule is simple: if the URLs do not change, a migration is a technical job; if the URLs change, a migration is an SEO project, and at its centre sits one thing — a permanent redirect map sending every old address to its new counterpart. Below you will find the four migration types, how to build and audit that map, the DNS and TTL plan, the order of operations on migration day, the numbers to watch afterwards, and the five mistakes that cost traffic.
Which migration are you doing?
Before starting, work out which box you are in; both the plan and the risk follow from it:
- Server or hosting change — the domain and URLs stay identical, only files and the database move. The lowest-risk scenario. What matters: downtime, and having the SSL certificate ready on the new server.
- Domain change — a rebrand, or moving from a country domain to .com. Even if the paths stay the same, every address changes, so a full redirect map is mandatory.
- Protocol or subdomain change — http to https, or switching between the www and bare versions. It looks small, but all four variants (http/https × www/bare) have to end up at a single canonical address.
- Platform or URL structure change — moving off WordPress, restructuring categories, adding locale prefixes. The riskiest scenario, and the one where the redirect map has to be built page by page.
One question measures your risk: after the migration, what happens when someone types an old address into a browser? If the answer is "the same page opens", the risk is low. If it is "404", you are throwing away everything you have built up in search.
Before you move: take inventory
A redirect map cannot be written from memory; it is written from a list of real addresses. Collect from four sources and merge them:
- The current sitemap.xml — the addresses the site declares about itself. A starting point, but not enough: pages deleted over the years yet still indexed will not be in it.
- The Search Console pages report — the addresses Google actually knows. Every address receiving traffic must be on this list, and forgotten-but-ranking pages mostly surface here.
- Server access logs — the addresses actually requested over the last three to six months. Old addresses that earned links from other sites only show up here.
- Analytics — the landing page report. It shows which addresses bring traffic, and it sets the priority order in the map.
Merge and deduplicate the four lists, then sort by traffic. In practice a small share of addresses carries most of the traffic; the map has to be right for that share first. If reading your site’s current position in search is the difficulty, our article on why your website is not showing up on Google helps.
The redirect map: auditing chains and loops
Writing a map is easy; verifying one is hard. Three things burn traffic quietly: unmapped addresses (they land on 404), redirect chains (A→B→C, losing signal and speed at every hop) and loops (A→B→A, where the page never opens at all). The function below audits a map against all three before you migrate:
type RedirectMap = Map<string, string>;
/**
* Canonicalises an address for comparison: trailing slash, casing and tracking
* parameters are removed. Meaningful query parameters (e.g. ?page=2) are kept —
* dropping those would treat two different pages as one.
*/
const TRACKING = new Set(['utm_source', 'utm_medium', 'utm_campaign', 'gclid', 'fbclid']);
function normalize(raw: string): string {
const u = new URL(raw);
u.hostname = u.hostname.toLowerCase().replace(/^www\./, '');
u.protocol = 'https:';
u.hash = '';
for (const key of [...u.searchParams.keys()]) {
if (TRACKING.has(key)) u.searchParams.delete(key);
}
u.searchParams.sort();
if (u.pathname.length > 1 && u.pathname.endsWith('/')) {
u.pathname = u.pathname.slice(0, -1);
}
return u.toString();
}
type Verdict =
| { status: 'ok'; target: string }
| { status: 'chain'; target: string; hops: number }
| { status: 'loop'; path: string[] }
| { status: 'missing' };
/** Finds the final target of an address, watching for chains and loops. */
function resolve(from: string, map: RedirectMap, maxHops = 5): Verdict {
const seen: string[] = [];
let current = normalize(from);
let hops = 0;
while (map.has(current)) {
if (seen.includes(current)) return { status: 'loop', path: [...seen, current] };
seen.push(current);
current = normalize(map.get(current)!);
hops += 1;
if (hops > maxHops) return { status: 'loop', path: [...seen, current] };
}
if (hops === 0) return { status: 'missing' };
return hops === 1
? { status: 'ok', target: current }
: { status: 'chain', target: current, hops };
}
export function auditRedirects(oldUrls: string[], map: RedirectMap) {
const report = { ok: 0, chains: [] as string[], loops: [] as string[], missing: [] as string[] };
for (const url of oldUrls) {
const v = resolve(url, map);
if (v.status === 'ok') report.ok += 1;
else if (v.status === 'chain') report.chains.push(url); // flatten the map
else if (v.status === 'loop') report.loops.push(url); // stop the migration
else report.missing.push(url); // 404 risk
}
return report;
}The audit output maps onto three actions in a clear order: if there is a loop, the migration does not start; chains get flattened to a single hop in the map (write A→C); unmapped addresses either get a correct target or a deliberate 410. "Let us just redirect everything to the homepage" is the most common and most expensive shortcut: Google reads that as a soft 404 rather than a redirect, and none of the page’s accumulated value transfers.
Redirect codes: 301 or 302?
For a permanent move there is one correct answer: a permanent redirect, 301 or 308. The temporary 302 and 307 tell a search engine "the old address is coming back" and do not consolidate signals. In practice this gets missed in two places: a framework’s default redirect helper sometimes returns a temporary code, and a rule written at the server or CDN layer shadows the one in the application. Checking ten random old addresses after the migration and reading the returned status code is the fastest way to catch it. Redirects also have to stay consistent with in-body links: if menus and content on the new site still point to old addresses, every click generates an unnecessary redirect hop.
The DNS and TTL plan
A DNS change does not propagate instantly; resolvers around the world cache the record for as long as its TTL. So there is exactly one preparation that belongs days before the migration rather than on the day: lowering the TTL.
- Lower the TTL 48 hours ahead (for example from 3600 seconds to 300). Propagation at cutover then takes minutes rather than hours.
- Do not switch the old server off immediately. For the length of the TTL some visitors keep reaching it; keep both alive for at least 48-72 hours.
- Freeze writes during the cutover window. With two servers live, a form submission or an order can land in two different databases — the scenario that loses the most data in migrations.
- Restore the TTL to its previous value once the move is done. Leaving it at 300 permanently just generates extra DNS lookups.
- Make email records (MX, SPF, DKIM, DMARC) a separate checklist item. Forgetting them while moving the web server is the number one reason email quietly stops working; we covered the setup side in the cost of business email.
Migration day: the order matters
The sequence of steps causes more errors than the steps themselves. The order that works:
- Prepare the new environment and keep it closed. The site should be fully working on the new server but closed to search engines — a staging address must be both blocked in robots and password protected. Otherwise the staging address gets indexed and competes with the real site.
- Test the redirect map in the new environment. The audit report must show zero loops and zero chains.
- Have the SSL certificate ready on the new server. Installed after cutover, it means browser warnings; the cost and process side is in the cost of an SSL certificate.
- Sync the data one last time and freeze writes. This happens immediately before cutover, not days earlier.
- Switch DNS. From this moment both servers have to stay up.
- Remove the staging block and verify live: ten old addresses, ten new ones, a form submission, the payment flow, and all four canonical variants.
- Update sitemap.xml with the new addresses and submit it. If the domain changed, use the change-of-address tool and create a separate property for the new domain.
If this is part of a redesign, it has to be planned together with the design and content decisions; we covered when and how in website redesign.
After the migration: which numbers matter?
Some fluctuation in the first four weeks is normal; decide in advance which numbers you will watch so you do not make a panic decision.
- Crawled and indexed page counts. New addresses enter the index as old ones drop out; the sum of the two should stay stable. If new addresses are not entering, something is wrong in the redirects or in robots.
- The 404 count. Check Search Console and server logs daily for the first week; every new 404 is a line to add to the map.
- Total clicks and impressions. Read them by cluster, not page by page: one page dropping is normal, an entire cluster dropping is a redirect error.
- Page speed. If the new server is slower, the gain turns into a loss; we set out the measurement set in what Core Web Vitals are.
- Recovery time. Days if the URL structure did not change, a few weeks if the domain did. If there is still no recovery in week four, audit the map again from scratch.
Five mistakes that cost you traffic
- Skipping the redirect map, or sending everything to the homepage. A bulk homepage redirect is read as a soft 404 and transfers nothing.
- Using temporary redirects. 302 and 307 do not consolidate signals; a permanent move needs 301 or 308.
- Leaving the staging environment open to search engines. An indexed test address cannibalises the real site and takes weeks to clean up.
- Forgetting to remove robots.txt blocks or noindex tags from the new environment. This is the quietest and most destructive migration error: the site opens, works, and falls out of the index.
- Switching the old server off on the day DNS changes. Visitors still arriving during the TTL window get errors, and that outage reaches search engines too.
Conclusion
The hard part of a website migration is not copying files; it is making sure every old address permanently reaches its new counterpart. So start with inventory, audit the map against chains and loops, lower the TTL two days ahead, and leave the old server up for at least 48 hours. If your URLs are not changing, this is maintenance; if the domain or the URL structure is changing, it is an SEO project and should be planned as one. If you are planning a migration, or doing it alongside a redesign, take a look at our web development service or request a quote with a note about your current page count and the URL structure that will change.