DEV Community

Cover image for Website redesign without losing SEO: a Sanity + Next.js checklist
Nayan Kyada
Nayan Kyada

Posted on Originally published at nayankyada.com

Website redesign without losing SEO: a Sanity + Next.js checklist

Most teams that lose traffic after a website redesign without planning for SEO did not get penalised. They changed URLs without redirects, dropped titles and headings that were ranking, or shipped a site that Google could not crawl cleanly. If you are rebuilding onto Sanity + Next.js, every one of those risks is preventable with a checklist and a few hours of discipline before launch.

What rankings loss after a redesign looks like

The pattern is consistent. In the first week you see a dip in Google Search Console impressions, usually modest. By week three or four, pages that used to rank on page one are on page three, and the pages that fell are the ones whose URL, title or main heading changed.

The common symptoms:

  • A spike of 404 errors in the Pages report in Search Console.
  • Indexed pages dropping while "Crawled, currently not indexed" or "Discovered, currently not indexed" grows.
  • Branded searches holding steady while non-branded searches fall. That means the homepage survived but the long tail did not.
  • Backlinked pages losing position because the link equity now points at a dead URL.

The cost of ignoring this is lopsided. A redesign takes weeks to build, but lost rankings can take months to recover, and you pay for that in lost leads the whole time. A pre-launch SEO pass is the cheapest part of the project.

The checklist

Here is the order I work in. Each row has a clear owner and a clear pass or fail.

Step What to do Pass condition
1. URL inventory Export every indexed and linked URL from a crawl, GSC, your analytics and backlink tool One sheet, deduplicated, with traffic and link counts
2. Decide the fate of each URL Keep, merge, or retire Every row has an action
3. 301 map Map old URL to new URL, one hop only No chains, no loops, no redirects to the homepage as a default
4. Metadata parity Carry over title, meta description, canonical, Open Graph Staging matches the old site for every kept URL
5. Heading and content parity Keep the H1 and the body copy that ranks Key pages diffed against the live site
6. Structured data Rebuild JSON-LD for the same types you had Rich Results Test passes on staging
7. Sitemap and robots Generate from Sanity, remove the staging noindex sitemap.xml lists only 200 canonical URLs
8. Internal links Update links so they point at final URLs, not redirects Crawl shows no internal redirects
9. Launch day checks Test redirects, canonicals, robots and indexability Spot checks on the top 50 URLs
10. Post-launch monitoring Watch GSC and analytics daily for two weeks Anomalies investigated within a day

Build the URL inventory first

Do not trust the old CMS to tell you what URLs exist. Old sites accumulate tag pages, paginated archives, campaign landing pages and PDFs. Combine four sources: a full crawl of the live site, the Pages and Performance reports in Search Console, your analytics landing pages, and a backlink export from whichever tool you use.

Sort by traffic and by referring domains. The top few hundred URLs deserve individual attention. The long tail can be mapped by pattern. If you are coming from WordPress, my WordPress to Sanity migration walkthrough covers how slugs and content types translate.

Build the 301 map and keep it in code

The rule is one hop, to the most relevant page. Redirecting everything to the homepage is treated by Google as a soft 404 in many cases and wastes the link equity.

For a few hundred redirects, a static list in Next.js config is fine. For thousands, or for redirects editors need to manage, store them in Sanity and read them at build time.

// Redirects document query
*[_type == "redirect" && defined(source) && defined(destination)]{
  source,
  destination,
  permanent
}
Enter fullscreen mode Exit fullscreen mode
// next.config.ts
import type { NextConfig } from "next";
import { createClient } from "next-sanity";

const client = createClient({
  projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID!,
  dataset: process.env.NEXT_PUBLIC_SANITY_DATASET!,
  apiVersion: "2026-01-01",
  useCdn: false,
});

const nextConfig: NextConfig = {
  async redirects() {
    const rows = await client.fetch<
      { source: string; destination: string; permanent: boolean }[]
    >(
      `*[_type == "redirect" && defined(source) && defined(destination)]{source, destination, permanent}`
    );
    return rows.map((r) => ({
      source: r.source,
      destination: r.destination,
      permanent: r.permanent ?? true,
    }));
  },
};

export default nextConfig;
Enter fullscreen mode Exit fullscreen mode

Redirects in next.config.ts are read at build time, so a new redirect needs a redeploy. For a launch that is fine. Validate the sheet before you ship: no source equals a destination, no destination is itself a source, and every destination returns 200.

Metadata parity

Titles and descriptions that already rank should move across unchanged unless you have a reason to change them. The redesign is not the moment to rewrite every title tag, because you will not know which change caused a drop.

Model seoTitle, seoDescription and a canonical override in Sanity, import the old values, then render them through the metadata API.

// app/[slug]/page.tsx
import type { Metadata } from "next";
import { client } from "@/sanity/lib/client";

type Props = { params: Promise<{ slug: string }> };

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const { slug } = await params;
  const page = await client.fetch(
    `*[_type == "page" && slug.current == $slug][0]{title, seoTitle, seoDescription}`,
    { slug }
  );
  return {
    title: page?.seoTitle ?? page?.title,
    description: page?.seoDescription,
    alternates: { canonical: `/${slug}` },
  };
}
Enter fullscreen mode Exit fullscreen mode

Then diff staging against production. A simple crawl of both and a comparison of title, description, H1 and canonical for every kept URL catches most mistakes. Pay particular attention to canonicals: a staging hostname leaking into production canonicals is a classic launch-day failure.

Structured data, sitemap and robots

If the old site had Article, Product, FAQ or Organization markup, the new one needs equivalent markup. Losing it does not usually drop rankings directly, but it can cost you rich results and the click-through that comes with them. I cover the implementation in Next.js SEO: adding JSON-LD structured data.

Generate sitemap.xml from Sanity so it always reflects published content. Include only canonical URLs that return 200, and exclude drafts and noindex pages. On the robots side, staging should block crawlers, and production must not inherit that block. Check it on launch day, not the following week.

Launch day and the first two weeks

On launch day, submit the new sitemap in Search Console, spot check the top 50 URLs for the right status code, canonical and indexability, and confirm the redirect map works on production rather than just staging.

After that, monitor daily for two weeks:

  • Pages report: new 404s mean a URL was missed in the inventory. Add a redirect immediately.
  • Performance report: compare clicks for the top pages against the same period before launch.
  • Crawl stats: a sudden drop in crawl requests can point at a server or robots problem.
  • Core Web Vitals: a rebuild should improve these, and if it does not, see how to fix LCP on image-heavy pages.

Expect small fluctuations as Google reprocesses the site. A sustained drop concentrated in a group of pages is a signal to look at that group's URLs, titles and content first.

What to ask a developer before the rebuild

  • Will you produce a URL inventory and redirect map before design sign-off?
  • How will metadata be migrated, and can I see a staging diff against production?
  • Who owns Search Console monitoring after launch, and for how long?
  • What happens to URLs I decide to retire?

A developer who cannot answer these has not done a migration that mattered.

This is work I do. If you are planning a rebuild onto Sanity + Next.js, a migration starts from $3,000 and a performance and Sanity audit from $800, and you can see the details on the services and packages page.

Top comments (0)