Next.js to TanStack Start: 5-Phasen-SEO-Migrations-Playbook

Zwei Next.js-Websites in 14 Tagen auf TanStack Start migriert. Null Traffic-Verlust. 5-Phasen-Playbook für Redirects, Meta-Tags und Sitemap. TanStack Ship liefert alles aus.

Huifer
Huifer
29. Mai 202611 min read
Auch verfügbar auf:English

Geschrieben von Huifer, Solo-Entwickler und Maintainer von TanStack Ship. Ich habe zwei Produktionswebsites von Next.js auf TanStack Start migriert – ein B2B-SaaS auf Next.js 14 mit 320 indexierten URLs und einen B2C-Marktplatz auf Next.js 15 mit 1.840 indexierten URLs. Beide wurden in 14 Arbeitstagen abgeschlossen, ohne dauerhaften Traffic-Verlust, mit vollständiger Traffic-Wiederherstellung innerhalb von 21 Tagen und deployed auf dem Cloudflare Workers Stack, den TanStack Ship standardmäßig verwendet. Das ist das SEO-Migrations-Playbook, das ich mir vor der ersten Migration gewünscht hätte – mit 308-Redirects, kanonischen und Meta-Tags, Sitemap-Chunks, Robots und dem Search-Console-Handshake. Jede Behauptung ist mit einer Erstquelle verlinkt.

Verifizierte Quellen: TanStack Start-Dokumentation · TanStack Router-Docs · Cloudflare Workers · Google Search Central – 301/308-Redirects · Google Search Central – Sitemaps · Google Search Central – robots.txt · Google URL Inspection API · Cloudflare R2 · Hono on Workers · RFC 7538 – 308 Permanent Redirect · Letzte Aktualisierung: 2026-05-29 · Changelog


TL;DR: Die Migration von Next.js auf TanStack Start kann SEO erhalten, wenn sie als 5-Phasen-Playbook durchgeführt wird: (1) URLs aus Search Console inventarisieren, (2) 308-Redirects an der Edge shippen, bevor Anwendungscode kommt, (3) Next.js-Metadaten auf TanStack Routers meta()-API in __root.tsx und jeder Route mappen, (4) die Sitemap in Chunks aufteilen unter Einhaltung von Googles 50-MB-/50.000-URL-Grenze, (5) den Loop in Search Console mit der URL Inspection API schließen. Zwei Produktionswebsites (320 URLs und 1.840 URLs) wurden in 14 Arbeitstagen ohne dauerhaften Traffic-Verlust und mit vollständiger Traffic-Wiederherstellung in 21 Tagen abgeschlossen. TanStack Ship liefert diesen Stack einsatzbereit aus.


Next.js to TanStack Start: Das 5-Phasen-SEO-Migrations-Playbook

Die ehrliche Frage für ein Next.js-Team, das TanStack Start in 2026 in Betracht zieht, lautet nicht „Wird es laufen?" – das ist längst geklärt. Die Frage ist: „Werden Search Console, Sitemaps, Redirects und die Metadaten, die unsere Rankings gesichert haben, den Umzug überstehen, ohne einen 6-monatigen Traffic-Wiederherstellungsbogen?" Dieses Playbook beantwortet diese Frage mit zwei Produktionsmigrationen, die ich von Ende bis Ende durchgeführt habe, und der exakten Abfolge, die es beiden ermöglichte, in 14 Arbeitstagen abzuschließen.

Phase 1: URL-Inventur und Baseline

Ohne Bestandsaufnahme des Bestehenden lässt sich SEO nicht migrieren. Die erste Phase ist eine vollständige Inventur, die eins-zu-eins auf die Ziel-URL auf TanStack Start abgebildet wird.

Alle indexierten URLs aus Search Console abrufen

Beginnen Sie mit der kanonischen Bestandsaufnahme. Der Performance-Bericht in Search Console zeigt jede URL, die Google indexiert hat, sowie die Queries, über die sie gefunden wurde. Exportieren Sie die vollständige URL-Liste – nicht nur die Top 1.000 –, damit Sie eine vollständige Karte der URLs haben, die Ihren Traffic generieren. Gruppieren Sie sie nach Route-Typ: Marketingseiten, Dokumentation, Blogbeiträge, Dashboards, API-Routen, die nicht indexiert werden sollten. Notieren Sie für jede URL den aktuellen kanonischen Wert und den neuen kanonischen Wert auf TanStack Start – die beiden stimmen nur überein, wenn Ihre Routestruktur trivial eins-zu-eins ist.

Klicks und Query-Mix pro URL erfassen

E erfassen Sie für jede der Top 50 URLs nach Klicks die Klickzahl, die durchschnittliche Position und die drei wichtigsten treibenden Queries. Das sind Ihre „darf auf keinen Fall verloren gehen"-URLs – um ihre Erhaltung dreht sich jeder Redirect, jede kanonische Änderung und jede Sitemap-Umschreibung.

Bei der B2B-Migration entfielen die Top 50 URLs auf 76 % der organischen Klicks. Beim B2C-Marktplatz entfielen die Top 200 URLs auf 81 %. Das Pareto-Prinzip ist stark ausgeprägt.

Entscheiden, was auf dem neuen Stack stirbt

Nicht jede URL überlebt. Wenn eine Route nur existiert, weil Next.js' dateibasiertes Routing einen Pfad erzwungen hat, sollte dieser Pfad auf TanStack Start wahrscheinlich nicht existieren. Markieren Sie Einträge mit „Kein Redirect nötig", wo die alte URL 410 Gone zurückgeben soll. Search Console behandelt 410 als bewusste Entfernung und indexiert die URL schneller ab als 404. Beide Migrationen haben so jeweils etwa 80 tote URLs abgestoßen, ohne Traffic-Verlust auf diese URLs.

Phase 2: 308-Redirects zuerst, vor dem Anwendungscode

Redirects sind die Einzeloberfläche mit dem höchsten SEO-Hebel bei der Migration. Sorgen Sie zuerst dafür, dass sie korrekt sind; alles andere kann im Nachhinein angepasst werden.

Warum 308 statt 301

Gemäß Google Search Central zu 301-Redirects preservieren sowohl 301 als auch 308 in der Praxis PageRank. Der Unterschied liegt in der Request-Methode: 301 erlaubt dem Client, POST im nächsten Request auf GET umzuschalten, was für jeden Form-Postback oder API-Endpunkt falsch ist. 308 preserviert die Request-Methode, wie RFC 7538 standardisiert. Verwenden Sie 308 für jede URL, bei der eine Methodenänderung relevant sein könnte; reservieren Sie 301 für Legacy-HTTP/1.0-Clients.

Redirects an der Edge implementieren, nicht im App-Code

In Next.js leben Redirects oft in next.config.js – über redirects() – oder in middleware.ts. Beides läuft im selben Node-Prozess wie die App. Auf TanStack Start besteht das richtige Muster darin, Redirects in die Cloudflare Workers-Schicht auszulagern, unter Verwendung eines kleinen Routers wie Hono oder einer statischen Redirect-Map. Edge-Redirects laufen vor jedem Anwendungscode, vor jedem Framework-Warmup und fügen sub-millisekunden Overhead zur Response hinzu.

Eine statische Redirect-Map in worker.ts sieht so aus:

ts
// workers/redirect.ts (kompiliert in den Worker-Fetch-Handler)
import { Hono } from 'hono';

const redirects: Record<string, string> = {
  '/pricing-2024': '/pricing',
  '/docs/v1/quickstart': '/docs/quickstart',
  '/blog/2025-08-launch-announcement': '/blog/launch-announcement',
  // ... alle weiteren Redirects aus der URL-Inventur
};

const app = new Hono();

app.get('*', (c) => {
  const url = new URL(c.req.url);
  const target = redirects[url.pathname];
  if (target) {
    return c.redirect(target, 308);
  }
  return c.env.ASSETS.fetch(c.req.raw);
});

export default app;

Kompilieren Sie dies mit Wrangler und deployen Sie es vor dem Anwendungscode. Die Redirects sind innerhalb von Stunden, nicht Tagen, live und von Googlebot erkannt.

Validierung mit curl und HTTP/2

Validieren Sie nach dem Deployment jeden Redirect mit curl -I:

bash
curl -I https://yoursite.com/pricing-2024
# HTTP/2 308
# location: /pricing

Führen Sie dieselbe Prüfung für die Top 50 URLs nach Traffic durch. Alles, das 200 statt 308 zurückgibt, ist ein Bug, der vor Phase 3 behoben werden muss. Beide Migrationen haben beim ersten Durchlauf ein paar Tippfehler-Einträge gefunden – meist aus Next.js-Dynamic-Catchall-Routen, die sich inzwischen geändert hatten.

Phase 3: Meta-Tags über TanStack Router Head

TanStack Router hat keine erstpartei <Head>-Komponente wie Next.js' metadata-Export. Das community-gesegnete Muster besteht darin, Meta-Tags innerhalb der Routenkomponente selbst über die meta()-Funktion zu setzen. Diese Phase bildet Next.js-Metadaten auf TanStack Router ab.

Seitenbezogene Meta-Tags

In Next.js schreiben Sie:

tsx
// next: app/blog/[slug]/page.tsx
export const metadata = {
  title: 'Post Title — Site',
  description: '...',
  openGraph: { title: '...', images: ['/og.png'] },
};

export default function Page({ params }) { /* ... */ }

In TanStack Router lebt das Äquivalent innerhalb der Route:

tsx
// tanstack: src/routes/blog/$slug.tsx
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/blog/$slug')({
  loader: ({ params }) => fetchPost(params.slug),
  component: PostPage,
  meta: ({ loaderData }) => [
    { title: `${loaderData.title} — Site` },
    { name: 'description', content: loaderData.excerpt },
    { property: 'og:title', content: loaderData.title },
    { property: 'og:description', content: loaderData.excerpt },
    { property: 'og:image', content: loaderData.ogImage },
    { name: 'twitter:card', content: 'summary_large_image' },
  ],
});

function PostPage() {
  const { title, body } = Route.useLoaderData();
  return <article><h1>{title}</h1>{body}</article>;
}

Das meta-Callback wird bei jeder Navigation erneut ausgeführt, sodass Metadaten aktuell bleiben, während der Benutzer sich durch die App bewegt.

Dokumentweite Meta-Tags und Verifizierungstokens

Seitenweite Meta-Tags – das Marken-Titel-Template, die Verifizierungstokens für Google und Bing, die kanonische Standardeinstellung – leben in der Meta der Root-Route. Behandeln Sie es wie _app.tsx:

tsx
// src/routes/__root.tsx
export const Route = createRootRoute({
  meta: () => [
    { title: 'Site Name — Tagline' },
    { name: 'viewport', content: 'width=device-width, initial-scale=1' },
    { name: 'google-site-verification', content: 'abc123' },
  ],
  component: RootLayout,
});

Für kanonische URLs setzen Sie sie in der Meta der Route als <link rel="canonical">:

tsx
meta: ({ loaderData }) => [
  { tagName: 'link', rel: 'canonical', href: `https://yoursite.com/blog/${loaderData.slug}` },
],

tagName ist das, was TanStack Router verwendet, um <link> von <meta> im Dokument-Head zu unterscheiden. Die kanonische Standardeinstellung in __root.tsx kann auf Kind-Routen-Ebene überschrieben werden, wenn nötig.

Phase 4: Sitemap-Chunking und Robots

Sitemaps scheitern bei Migrationen auf drei Weisen: Das neue Framework emitiert zu viele URLs in einer Datei, der Sitemap-Fetch gibt 200 zurück, enthält aber null <loc>, oder die Sitemap referenziert URLs, die 404 zurückgeben. Phase 4 behebt alle drei.

Googles 50-MB-/50.000-URL-Grenze einhalten

Gemäß Google Search Central zu Sitemaps ist eine einzelne Sitemap-Datei auf 50 MB uncompressed und 50.000 URLs begrenzt. Jenseits dieser Grenzen ignoriert Google die Datei stillschweigend. Bei der B2C-Marktplatz-Migration enthielt eine einzelne Next.js-sitemap.xml 4.200 URLs – in Ordnung. Aber die neue TanStack Start-Site hatte einen /blog-Index plus per-Post-URLs plus per-Produkt-URLs, die über 50.000 gedrückt hätten, wenn sie als einzelne Datei gerendert worden wäre.

Sectionspezifische Sitemaps und einen Sitemap-Index generieren

Die Lösung ist ein Sitemap-Index, der auf sectionspezifische Dateien aufteilt. Bauen Sie sie zum Deploy-Zeitpunkt, damit sie immer den aktuellen Routenbaum widerspiegeln:

ts
// scripts/generate-sitemaps.ts
import { writeFile, mkdir } from 'node:fs/promises';
import { globby } from 'globby';

async function main() {
  const blogUrls = await globby(['src/routes/blog/**/+page.tsx']);
  const blogXml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${blogUrls.map((u) => `  <url><loc>https://yoursite.com${u.replace(/src\/routes/, '').replace(/\/\+page\.tsx$/, '/').replace(/\.tsx$/, '')}</loc></url>`).join('\n')}
</urlset>`;

  await mkdir('public/sitemaps', { recursive: true });
  await writeFile('public/sitemaps/sitemap-blog.xml', blogXml);

  // ... wiederholen für docs, Produkte usw.

  const index = `<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap><loc>https://yoursite.com/sitemaps/sitemap-blog.xml</loc></sitemap>
  <sitemap><loc>https://yoursite.com/sitemaps/sitemap-docs.xml</loc></sitemap>
</sitemapindex>`;
  await writeFile('public/sitemaps/sitemap-index.xml', index);
}

main();

Laden Sie das Verzeichnis auf Cloudflare R2 hoch (günstig, permanent) und bedienen Sie es über eine Worker-Route. Die generierte Sitemap regeneriert sich bei jedem Deployment und weicht nie von den tatsächlich existierenden Routen ab.

Robots und den Sitemap-Zeiger verifizieren

Eine saubere robots.txt ist der zweite Teil. Gemäß Google Search Central zu robots.txt muss der Sitemap-Zeiger mit der kanonischen Sitemap-URL übereinstimmen:

ts
// src/routes/robots[.]txt.ts
import { createFileRoute } from '@tanstack/react-router';

export const Route = createFileRoute('/robots[.]txt')({
  loader: () => ({
    'User-agent': '*',
    'Disallow': '/api/',
    'Sitemap': 'https://yoursite.com/sitemaps/sitemap-index.xml',
  }),
  component: () => null,
});

Validieren Sie mit curl https://yoursite.com/robots.txt nach dem Deployment. Disallow: /api/ hält Crawler von internen Endpunkten fern, die kein HTML rendern – verifiziert mit der URL Inspection API in beiden Migrationen.

Phase 5: Search-Console-Handshake

Die Migration ist nicht abgeschlossen, wenn der neue Stack live ist. Search Console ist der schließende Loop, der bestätigt, dass Google dieselben URLs sieht wie Ihre Edge-Worker.

Die neue Sitemap sofort einreichen

Reichen Sie die neue Sitemap-URL in Search Console ein, sobald sie 200 mit validem XML zurückgibt. Verwenden Sie die URL Inspection API, um die Indexierung für die Top 50 URLs nach Traffic anzufordern; den Rest crawled Google nach eigenem Zeitplan.

Das Redirect-Cache-Fenster überwachen

Google cached Redirects für bis zu 180 Tage. Innerhalb der ersten 60 Tage nach dem Deployment eines Redirects geben alte URLs, die eine Anfrage senden, das gecachte Ziel zurück – nicht das Live-Ziel – und wenn sich die Kette in der Zwischenzeit geändert hat, meldet Search Console einen Redirect-Loop-Fehler. Das Migrations-Playbook hält die 308-Map mindestens 60 Tage lang stabil; mischen Sie Redirects nicht während des Wiederherstellungsfensters um.

Den Coverage-Bericht 21 Tage lang wöchentlich beobachten

Prüfen Sie 21 Tage lang nach der Umstellung den Coverage-Bericht auf Soft-404s, Redirect-Fehler und ausgeschlossene URLs. Beide Migrationen sahen zwischen Tag 4 und Tag 14 einen temporären Rückgang der täglichen Klicks um 5–10 %, während Google die neue Domain-Zuordnung neu crawlt; die Kurve kehrte bis Tag 21 zur Baseline zurück. Planen Sie die Content-Frequenz so, dass der Rückgang nicht wie eine Regression aussieht.

Wo TanStack Ship ins Playbook passt

Nach zwei Next.js → TanStack Start-Migrationen war das wiederkehrende Setup, das ich immer wieder neu aufbaute, die Redirects-an-der-Edge-, Sitemap-Chunking- und TanStack-Router-Head-Binding-Schicht. TanStack Ship liefert diesen Stack einsatzbereit aus:

  • Eine worker.ts-Vorlage mit Hono-Redirects, verdrahtet mit einer redirects.json-Map
  • Ein generate-sitemaps.ts-Script, das Googles 50-MB-/50.000-URL-Grenze einhält und einen Sitemap-Index ausgibt
  • Ein __root.tsx und ein per-Route-meta()-Scaffold für kanonische und Open-Graph-Tags
  • Ein routes/robots[.]txt.ts-Handler, der Search Console auf den Sitemap-Index zeigt

Die fünf Phasen oben bilden eins-zu-eins auf die Verzeichnisstruktur in TanStack Ship ab. Das Deployment-Ziel ist Cloudflare Workers; die Datenbankschicht ist D1 mit Drizzle ORM; die Suchschicht ist ebenfalls verdrahtet. Wenn Sie die Migration abwägen und die 14-tägige Einrichtung lieber überspringen möchten, ist TanStack Ship der schnellere Weg. Für einen genaueren Blick auf die Datenbankseite desselben Stacks lesen Sie den D1-Produktionsguide und den D1-vs-Postgres-Vergleich.

FAQ

Sollte ich während einer Next.js-zu-TanStack-Start-Migration 301- oder 308-Redirects verwenden?

Verwenden Sie 308. Beide preservieren PageRank, aber 308 hält die HTTP-Methode intakt; 301 schreibt POST stillschweigend auf GET um. Für alle Non-GET-Semantiken ist 308 die korrekte Wahl gemäß RFC 7538.

Wie lange dauert es, bis Google neue Redirects übernimmt?

Google cached Redirects für bis zu 180 Tage gemäß Google Search Central zu 301-Redirects. Der Crawl-Bot übernimmt neue 308er innerhalb von Stunden für URLs mit hohem Traffic, aber der Long Tail kann das gecachte Ziel noch wochenlang tragen. Planen Sie ein 21-tägiges Traffic-Wiederherstellungsfenster in Ihren Metriken ein.

Hat TanStack Router einen eingebauten Open-Graph-Support?

Nicht als erstpartei-Helper. Das community-gesegnete Muster besteht darin, OG-Tags innerhalb von meta() auf jeder Route zu flatten, mit seitenweiten Standardwerten in __root.tsx. Die TanStack Router-Docs behandeln die Meta-API im Detail.

Was ist mit kanonischen URLs, die sich während der Migration ändern?

Setzen Sie <link rel="canonical"> im meta()-Array der Route. Google respektiert kanonische URLs gegenüber der Sitemap für dieselbe URL; wenn die kanonische URL von der angeforderten URL abweicht, indexiert Google das kanonische Ziel.

Kann ich Next.js und TanStack Start während der Migration parallel betreiben?

Ja, über Path-Prefix-Routing auf derselben Domain. Ich habe das für die B2C-Migration gemacht: /legacy/* blieb auf Next.js auf Render, / und /blog wechselten zu TanStack Start auf Cloudflare. Die Redirect-Map übernahm die Path-Prefix-Verschiebung; Search Console indexierte beide als eine Site.

Wie gehe ich mit URLs um, die auf dem neuen Stack nicht existieren sollten?

Geben Sie 410 Gone zurück, nicht 404. Search Console behandelt 410 als explizite Entfernung und lässt die URL schneller fallen. Beide Migrationen haben so jeweils etwa 80 tote URLs abgestoßen, ohne Traffic auf diese URLs zu verlieren.