SEO für Next.js, React und Nuxt

Vadim Kravcenko
Vadim Kravcenko
· 18 min read

TL;DR: JavaScript-Frameworks zerstören SEO standardmäßig. Beim Client-Side Rendering sehen Suchmaschinen eine leere Hülle — und KI-Crawler führen JavaScript überhaupt nicht aus. Next.js (mit Server Components und der Metadata API) ist derzeit die beste Option für SEO. Nuxt liegt für Vue-Setups nur knapp dahinter. Reine React-SPAs sollten niemals für Seiten verwendet werden, die indexiert werden sollen. In diesem Leitfaden bekommst du den exakten Code, die exakten Fehler und die exakten Fixes. Ohne Schönreden.

Das grundlegende Problem: JavaScript und Suchmaschinen verstehen sich nicht

Googlebot JavaScript processing pipeline showing crawling, rendering, and indexing phases
So verarbeitet Googlebot JavaScript: Die Seiten durchlaufen separate Phasen für Crawling, Rendering und Indexierung, was die Auffindbarkeit von Inhalten verzögern kann. Quelle: Google Search Central

Die Regel: Wenn eine URL in der Suche ranken oder von KI zitiert werden soll, muss sie im ersten Antwort-Response vollständiges HTML liefern. Das ist alles. „Aber Google kann JavaScript rendern“ — ja, irgendwann, unzuverlässig, nach einer Warteschlange, die Tage dauern kann, auf einer Infrastruktur, die Google mit extrem hohen Kosten betreibt – genau deshalb, weil so viele Entwickler leere HTML-Hüllen ausliefern und erwarten, dass die Suchmaschine die Rendering-Arbeit für sie erledigt. Und KI-Crawler fangen damit nicht mal an.

ISR ist… Moment, ich hole kurz aus. Früher dachte ich, ISR sei in den meisten Fällen ein klarer Gewinner gegenüber SSR. Nach dem Ansehen von Revalidierungs-Bugs, durch die wochenlang veraltete Inhalte auf ein paar Kundenseiten bestehen blieben, bin ich weniger sicher. Auf der E-Commerce-Seite eines Kunden lieferten ISR-Seiten veraltete Preise noch 6 Stunden aus — weil die Revalidierung still fehlschlug: kein Fehler in den Logs, keine Meldung, nur falsche Preise für Kunden und Crawler. ISR ist großartig, wenn es funktioniert. Wenn nicht, ist das Debuggen von veralteten Cache-Problemen wirklich schmerzhaft. SSR ist planbarer, auch wenn es etwas langsamer ist.

Next.js SEO: Der Deep Guide

Next.js bekommt den längsten Abschnitt, weil es ihn verdient. Es ist das beliebteste React-Framework, und seit der App Router in Next.js 13+ der Default ist, ist es das beste JavaScript-Framework für SEO. Nicht knapp — sondern messbar besser als die Alternativen.

Wenn du 2026 ein neues Projekt baust und SEO wichtig ist, nutze Next.js mit dem App Router. Das ist die Empfehlung. Der Rest dieses Abschnitts erklärt, warum.

App Router vs. Pages Router — SEO-Auswirkungen

Next.js hat zwei Routing-Systeme. Der App Router (eingeführt in Next.js 13, stabil in 14+) und der Legacy Pages Router. Beide können zu guten SEO-Ergebnissen führen, aber der App Router ist in fast jeder Hinsicht besser, die für Suchmaschinen zählt:

  • Server Components standardmäßig — Komponenten rendern auf dem Server, außer du fügst explizit 'use client' hinzu. Weniger ausgeliefertes JavaScript bedeutet schnellere Seiten und vollständiges HTML für Crawler.
  • Streaming-SSR — Der Server beginnt sofort mit dem Senden von HTML, bevor alle Daten abgeholt wurden. TTFB verbessert sich. Googlebot bekommt Inhalte schneller.
  • Integrierte Metadata API — Metadaten-Generierung pro Route, typgesichert. Keine Drittanbieter-Pakete mehr für Meta-Tags.
  • Verschachtelte Layouts — Gemeinsame UI bleibt über Navigations hinweg erhalten, ohne neu gerendert zu werden, was die Core Web Vitals verbessert.

Der Pages Router funktioniert weiterhin zuverlässig. Wenn du eine große bestehende Codebase darauf hast, brauchst du nicht in Panik zu migrieren.

Aber bei neuen Projekten? App Router, ohne Frage.

Die Metadata API (das ist der große Punkt)

Vor dem App Router bedeutete Next.js SEO: next-seo installieren und Meta-Tags manuell verdrahten. Die Metadata API — die ich trotz meiner Kritik an dem Migrationsaufwand zu den besten Dingen am App Router zähle — löst das sauber als erstklassige Framework-Funktion.

Statische Metadaten für eine Seite:

// app/about/page.tsx
import { Metadata } from 'next'

export const metadata: Metadata = {
  title: 'Über uns | Ihr Unternehmen',
  description: 'Wir bauen Tools, die SEO automatisch machen.',
  openGraph: {
    title: 'Über uns',
    description: 'Wir bauen Tools, die SEO automatisch machen.',
    type: 'website',
  },
  alternates: {
    canonical: 'https://example.com/about',
  },
  robots: {
    index: true,
    follow: true,
  },
}

Dynamische Metadaten für Seiten mit Parametern (Blogposts, Produkte usw.):

// app/blog/[slug]/page.tsx
import { Metadata } from 'next'

type Props = { params: { slug: string } }

export async function generateMetadata({ params }: Props): Promise<Metadata> {
  const post = await getPost(params.slug)

  return {
    title: `${post.title} | Ihr Blog`,
    description: post.excerpt,
    openGraph: {
      title: post.title,
      description: post.excerpt,
      type: 'article',
      publishedTime: post.publishedAt,
      authors: [post.author.name],
      images: [{ url: post.ogImage, width: 1200, height: 630 }],
    },
    alternates: {
      canonical: `https://example.com/blog/${params.slug}`,
    },
  }
}

export default async function BlogPost({ params }: Props) {
  const post = await getPost(params.slug)

  return (
    <article>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </article>
  )
}

Das ist eine Server Component. Kein 'use client'-Directive. Sie läuft komplett auf dem Server. Das HTML, das bei Googlebot ankommt, enthält den vollständigen Artikel inklusive aller Meta-Tags. Kein JavaScript-Rendering erforderlich.

Den häufigsten Fehler sehe ich ständig: Entwickler packen ihr Data Fetching in eine 'use client'-Komponente — das heißt: Der Inhalt lädt per JavaScript, nachdem das initiale HTML bereits gesendet wurde. Googlebot bekommt eine leere Seite. Ernsthaft. Verschiebe dein Data Fetching in Server Components oder generateMetadata. Und wenn du nicht sicher bist, ob eine Komponente server- oder clientseitig ist: Prüfe oben in der Datei nach der 'use client'-Directive — ist sie da, befindet sich nichts in diesem Component-Tree im initialen HTML-Response.

Sitemap-Generierung

Der Next.js App Router hat natives Sitemap-Support. Lege app/sitemap.ts an, und es wird automatisch unter /sitemap.xml generiert:

// app/sitemap.ts
import { MetadataRoute } from 'next'

export default async function sitemap(): MetadataRoute.Sitemap {
  const posts = await getAllPosts()
  const products = await getAllProducts()

  const postEntries = posts.map((post) => ({
    url: `https://example.com/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt),
    changeFrequency: 'weekly' as const,
    priority: 0.7,
  }))

  const productEntries = products.map((product) => ({
    url: `https://example.com/products/${product.slug}`,
    lastModified: new Date(product.updatedAt),
    changeFrequency: 'daily' as const,
    priority: 0.8,
  }))

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postEntries,
    ...productEntries,
  ]
}

Für Sites mit mehr als 50.000 URLs nutze generateSitemaps(), um mehrere Sitemap-Dateien zu erstellen. Googles Limit liegt bei 50.000 URLs pro Sitemap-Datei.

robots.ts

Gleiches Muster. Lege app/robots.ts an:

// app/robots.ts
import { MetadataRoute } from 'next'

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [
      {
        userAgent: '*',
        allow: '/',
        disallow: ['/api/', '/dashboard/', '/admin/'],
      },
    ],
    sitemap: 'https://example.com/sitemap.xml',
  }
}

Dynamische OG-Bilder

Next.js kann Open Graph Images on-the-fly mit next/og generieren (basierend auf der Satori-Library von Vercel). Das ist praktisch — statt OG-Bilder für jeden Blogpost manuell zu erstellen, definierst du ein Template und es rendert zur Anfragezeit:

// app/blog/[slug]/opengraph-image.tsx
import { ImageResponse } from 'next/og'

export const size = { width: 1200, height: 630 }
export const contentType = 'image/png'

export default async function Image({
  params,
}: {
  params: { slug: string }
}) {
  const post = await getPost(params.slug)

  return new ImageResponse(
    (
      <div style={{
        display: 'flex',
        flexDirection: 'column',
        justifyContent: 'center',
        padding: '60px',
        background: 'white',
        width: '100%',
        height: '100%',
      }}>
        <h1 style={{ fontSize: 48, fontWeight: 700 }}>
          {post.title}
        </h1>
        <p style={{ fontSize: 24, color: '#666' }}>
          {post.excerpt}
        </p>
      </div>
    ),
    { ...size }
  )
}

Next.js setzt automatisch das og:image-Meta-Tag so, dass es auf dieses generierte Bild zeigt. Kein manuelles Verdrahten nötig.

Bildoptimierung mit next/image

Der next/image-Komponent kümmert sich um Lazy Loading, automatische WebP/AVIF-Konvertierung, responsives Sizing und verhindert Layout Shift (CLS). All das wirkt direkt auf die Core Web Vitals ein, die Google als Ranking-Signal nutzt.

import Image from 'next/image'

// Das wird automatisch gemacht:
// - Generiert WebP/AVIF-Varianten
// - Lazy lädt Bilder unterhalb des sichtbaren Bereichs
// - Setzt width/height, um CLS zu verhindern
// - Liefert responsive Größen
<Image
  src="/hero.jpg"
  alt="Produktscreenshot mit dem Dashboard"
  width={1200}
  height={630}
  priority  // Above-the-fold: Lazy Loading deaktivieren
/>

Zwei Dinge machen Entwickler besonders oft falsch: Sie vergessen priority beim LCP-Bild (dein größtes Bild oberhalb des sichtbaren Bereichs) und sie verwenden rohe <img>-Tags statt next/image. Beides verschlechtert Core Web Vitals.

Strukturierte Daten in Next.js

Füge JSON-LD strukturierte Daten direkt in deine Server Components ein. Kein Drittanbieter-Paket nötig:

// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }) {
  const post = await getPost(params.slug)

  const jsonLd = {
    '@context': 'https://schema.org',
    '@type': 'Article',
    headline: post.title,
    description: post.excerpt,
    datePublished: post.publishedAt,
    dateModified: post.updatedAt,
    author: {
      '@type': 'Person',
      name: post.author.name,
    },
    image: post.ogImage,
  }

  return (
    <>
      <script
        type="application/ld+json"
        // In Next.js Server Components ist das sicher —
        // das JSON wird serverseitig aus deiner eigenen Datenbank generiert
        {...{ children: JSON.stringify(jsonLd) }}
      />
      <article>
        <h1>{post.title}</h1>
        <p>{post.content}</p>
      </article>
    </>
  )
}

Häufige SEO-Fehler in Next.js

Ich sehe diese Probleme auf nahezu jeder Next.js-Site, die ich auditiere. Jeder einzelne davon kostet Rankings.

  • Data Fetching in 'use client'-Komponenten — Dein Inhalt lädt erst, nachdem JavaScript gelaufen ist. Googlebot sieht einen leeren Loading-Spinner. Verschiebe das Data Fetching in Server Components.
  • Fehlende kanonische URLs — Next.js setzt canonicals standardmäßig nicht. Wenn du /blog/my-post und /blog/my-post?ref=twitter beide indexiert hast, teilst du die Autorität. Setze alternates.canonical in deinen Metadaten.
  • Keine Metadaten auf dynamischen Routen — Statische Seiten bekommen den metadata-Export. Dynamische Seiten brauchen generateMetadata. Ich habe Sites gesehen, die auf der Homepage perfekte Metadaten hatten und auf jeder Produktseite <title>undefined</title> — super aussagekräftig.
  • loading.tsx für kritischen Content nutzen — Die Loading-Datei zeigt einen Skeleton, während der Inhalt gestreamt wird. Googlebot kann den Skeleton statt des echten Inhalts indexieren. Nutze loading.tsx für nicht-kritische UI, nicht für den Content der Hauptseite.
  • Client-seitige Redirects — Redirects mit router.push(). Suchmaschinen führen JavaScript-Redirects nicht zuverlässig aus. Nutze Redirects in next.config.js oder Middleware für serverseitige 301/302s.

React SPA SEO: Meistens „Lass es“

Ich bin genervt, dass ich diesen Abschnitt schreiben muss. Es ist 2026. (Wenn du für eine öffentliche Seite in 2026 noch Create React App nutzt, müssen wir reden.) Aber die E-Mails kommen weiter — also sind wir hier.

Nutze keine schlichte React-SPA für Seiten, die indexiert werden sollen. Das ist der Kern. Eine reine React-SPA — Create React App, Vite mit React, egal was — liefert jeder Crawler-Visit eine leere HTML-Hülle. Google könnte sie irgendwann rendern. KI-Crawler niemals. Nutze sie für Dashboards, Admin-Panels und alles, was hinter einem Login steckt. Nicht verwenden, wenn es in Suchergebnissen auftauchen soll.

Übergangslösung: React Helmet + Prerendering

Wenn du mit einer React-SPA festhängst und nicht auf Next.js migrieren kannst (ich weiß — passiert), dann ist das die Bastellösungs-Variante:

// Mit react-helmet-async für Meta-Tags
import { Helmet } from 'react-helmet-async'

function ProductPage({ product }) {
  return (
    <>
      <Helmet>
        <title>{product.name} | Ihr Shop</title>
        <meta name="description" content={product.description} />
        <link rel="canonical"
          href={`https://example.com/products/${product.slug}`} />
      </Helmet>
      <h1>{product.name}</h1>
    </>
  )
}

React Helmet verwaltet deine <head>-Tags. Aber — und das ist entscheidend — es läuft weiterhin clientseitig. Googlebot muss JavaScript rendern, um diese Tags zu sehen. Du brauchst einen Prerendering-Service (Prerender.io, Rendertron oder dein eigenes Puppeteer-Setup), um Crawlern vorgerenderte HTML auszuliefern.

Das funktioniert. Ich habe es gesehen. Aber es ist fragil, fügt Latenz bei Crawler-Anfragen hinzu, kostet Geld, und du arbeitest gegen das Framework statt mit ihm.

Wenn deine SPA mehr als 50 Seiten hat, die indexiert werden sollen — und diese Seiten dynamischen Inhalt haben, der sich wöchentlich ändert, das heißt: Der Prerendering-Cache muss ständig invalidiert werden, das heißt: Jemand in deinem Team pflegt jetzt Crawler-Infrastruktur statt Produktfeatures zu bauen — dann übersteigen die Wartungskosten für ein Prerendering-Setup die Kosten einer Migration auf Next.js. Ich habe diese Zahlen für Kund:innen durchgerechnet.

Wie Addy Osmani und Jason Miller in web.dev dokumentiert haben, führt Prerendering typischerweise zu spürbarer serverseitiger Latenz pro Seite bei Crawler-Anfragen. Dazu kommen häufig Edge Cases mit dynamischem Content oder authentifizierten Zuständen, die zu veralteten oder falschen Snapshots führen. Das ist eine valide Brückenstrategie, aber keine Dauerlösung (web.dev: Rendering on the Web).

Nuxt SEO: Die Vue-Entsprechung

Wenn dein Team im Vue-Ökosystem unterwegs ist, ist Nuxt für Vue das, was Next.js für React ist. Gleiche Idee: ein Client-Framework nehmen, Server Rendering, Metadata-Management und filebasiertes Routing ergänzen. (Ich muss fairerweise sagen: Ich habe deutlich weniger Zeit mit Nuxt verbracht als mit Next.js, also nimm meine Einschätzungen hier bitte mit extra Salz.) Die SEO-Story ist stark — nicht ganz so poliert wie Next.js in ein paar Bereichen, aber so nah dran, dass es kein entscheidender Faktor zwischen den beiden Ökosystemen sein sollte.

SSR ist der Default

Nuxt nutzt universal Rendering out of the box. Jede Seite wird beim ersten Laden servergerendert und danach für die Navigation im Client hydratisiert. Du musst nicht aktivieren. Du musst deaktivieren. Das ist der richtige Default für SEO.

useHead() und useSeoMeta()

Das Metadaten-System von Nuxt über Composables ist sauber. Zwei Optionen — je nachdem, wie viel Kontrolle du brauchst:

<!-- pages/blog/[slug].vue -->
<script setup>
const route = useRoute()
const { data: post } = await useFetch(`/api/posts/${route.params.slug}`)

// Option 1: useSeoMeta — typgesichert, deckt die gängigen Fälle ab
useSeoMeta({
  title: () => post.value?.title,
  description: () => post.value?.excerpt,
  ogTitle: () => post.value?.title,
  ogDescription: () => post.value?.excerpt,
  ogType: 'article',
  ogImage: () => post.value?.ogImage,
  twitterCard: 'summary_large_image',
})

// Option 2: useHead — volle Kontrolle über <head>-Tags
useHead({
  link: [
    {
      rel: 'canonical',
      href: `https://example.com/blog/${route.params.slug}`,
    }
  ],
  script: [
    {
      type: 'application/ld+json',
      innerHTML: JSON.stringify({
        '@context': 'https://schema.org',
        '@type': 'Article',
        headline: post.value?.title,
        datePublished: post.value?.publishedAt,
      }),
    },
  ],
})
</script>

<template>
  <article>
    <h1>{{ post?.title }}</h1>
    <p>{{ post?.content }}</p>
  </article>
</template>

useSeoMeta() gefällt mir sehr. Es ist meinungsstärker als die Metadata API von Next.js, deckt aber 90% dessen ab, was du brauchst — mit weniger Boilerplate. Die Typsicherheit bedeutet, dass dein IDE Tippfehler in Meta-Tag-Namen findet — etwas, das echte Bugs verursacht hat, die ich bei Projekten gesehen habe.

Hybrides Rendering mit Route Rules

Mit Nuxts routeRules kannst du Rendering-Strategien pro Route mischen. Das ist eine der Stellen, an denen Nuxt aus Entwicklersicht sogar wahrscheinlich vor Next.js liegt:

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/':              { prerender: true },     // SSG — Startseite
    '/blog/**':       { isr: 3600 },           // ISR — jede Stunde revalidieren
    '/products/**':   { ssr: true },           // SSR — immer aktuell
    '/dashboard/**':  { ssr: false },          // CSR — authentifizierte Seiten
    '/docs/**':       { prerender: true },     // SSG — Dokumentation
  }
})

Ein Konfigurationsobjekt, fünf verschiedene Rendering-Strategien. Bei Next.js würdest du export const dynamic = 'force-static' oder export const revalidate = 3600 in jeder einzelnen Seiten-Datei setzen. (Ganz fair: Das ist nicht komplett fair — Next.js-Middleware kann das auch teilweise zentral übernehmen. Aber Nuxts Ansatz ist deutlicher.) (Das erinnert mich an das Debuggen der Gatsby-GraphQL-Schicht um 2 Uhr nachts — manche Frameworks optimieren für Developer Experience auf Kosten der eigenen geistigen Stabilität.) Nuxts Ansatz skaliert besser, wenn du klare Muster auf Routenebene hast.

Sitemap-Modul

Nuxt hat keine eingebaute Sitemap-Generierung wie Next.js. Du brauchst das @nuxtjs/sitemap-Modul (offiziell gepflegt und gut unterstützt):

// nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxtjs/sitemap'],

  sitemap: {
    sources: ['/api/__sitemap__/urls'],
    exclude: ['/dashboard/**', '/admin/**'],
  },

  site: {
    url: 'https://example.com',
  },
})

Das Modul entdeckt deine statischen Seiten automatisch über das filebasierte Routing. Für dynamische Seiten (Blogposts, Produkte) stellst du einen API-Endpunkt bereit, der die URL-Liste zurückliefert. Sitemap-Indexdateien werden automatisch generiert, sobald du über 50.000 URLs kommst.

Nuxt Content für Blog/Docs

Wenn du mit Nuxt einen Blog oder eine Dokumentationsseite baust, lohnt sich das @nuxt/content-Modul. Es liest Markdown/MDX-Dateien aus einem content/-Verzeichnis, erzeugt Pages mit vollem SSG-Support und bringt eine integrierte Suche mit. Für SEO liegt der entscheidende Vorteil darin, dass jede Content-Seite als statisches HTML vorgerendert wird — die schnellste mögliche Auslieferung an Suchmaschinen.

War Story: Die Migration, die meine Meinung geändert hat

Google Lighthouse SEO audit score showing passed and failed SEO checks
Lighthouse-SEO-Audit-Scores bewerten deine Seite anhand von Meta-Tags, Crawlability und Mobile-Friendliness. Quelle: Semrush Blog

Fix: Server-render deinen kritischen Content. Wenn du Ladezustände brauchst, stelle sicher, dass sie nur für nicht-kritische UI-Elemente erscheinen. Verifizieren: Deaktiviere JavaScript in Chrome DevTools (Settings > Debugger > Disable JavaScript) und lade die Seite neu. Was du siehst, sehen die meisten Crawler. Wenn du einen Spinner siehst, sieht ihn auch Google.

4. Fehlende strukturierte Daten

JSON-LD strukturierte Daten helfen Suchmaschinen zu verstehen, worum es auf deiner Seite geht. Produktseiten ohne Product-Schema. Blogposts ohne Article-Schema. FAQ-Seiten ohne FAQPage-Schema. Jede fehlende Schema-Art ist eine verpasste Chance auf Rich Results.

Fix: Füge JSON-LD für jeden Seitentyp hinzu. Verifizieren: Starte Googles Rich Results Test für jeden Seitentyp. Sowohl Next.js als auch Nuxt machen das einfach — siehe die Codebeispiele oben. Oder lass SEOJuice das automatisch übernehmen.

5. Client-seitige Redirects

Redirects mit JavaScript (window.location.href, router.push(), navigateTo()) statt serverseitige 301/302s. Suchmaschinen folgen JavaScript-Redirects nicht zuverlässig. Link-Equity wird nicht sauber übertragen. Seiten, die konsolidiert werden sollten, bleiben getrennt.

Fix: Nutze serverseitige Redirects. In Next.js konfigurierst du sie in next.config.js oder verwendest Middleware. In Nuxt nutzt du routeRules für Redirects. Verifizieren: curl -I https://your-site.com/old-url — du solltest einen 301- oder 302-Statuscode mit einem Location-Header sehen. Wenn du 200 OK siehst, ist der Redirect nur clientseitig.

6. KI-Crawler komplett vergessen

Das ist das Neue. Selbst wenn dein SSR-Setup für Googlebot perfekt ist, prüfe, ob deine robots.txt KI-Crawler blockiert. Manche CDN-Anbieter (insbesondere Cloudflare mit dem Toggle „AI Bot“) blockieren GPTBot und ähnliche Crawler standardmäßig. Wenn du Sichtbarkeit in KI-Suchmaschinen willst, stelle sicher, dass sie auf deinen Content zugreifen können. Verifizieren: curl https://your-site.com/robots.txt und suche nach GPTBot, ClaudeBot, PerplexityBot. Wenn sie disallowt sind und du sie nicht selbst dort eingetragen hast, hat dein CDN das getan.

Und ein letzter Check, der alles oben abdeckt: Rechtsklick auf irgendeine Seite, „Quelltext anzeigen“. Wenn dein Content im rohen HTML steckt, funktioniert serverseitiges Rendering. Wenn du ein leeres <div id="root"></div> siehst, dann nicht. Laufe außerdem Lighthouse’s SEO-Audit durch — Zielwert 100, das ist mit serverseitigem Rendering erreichbar. Wie Jason Miller und Addy Osmani auf web.dev geschrieben haben: Rendering-Strategien beinhalten echte Trade-offs, und du kannst es dir nicht leisten anzunehmen, dass jedes Crawler-JavaScript korrekt ausgeführt wird (web.dev: Rendering on the Web).

Der ehrliche Standpunkt

Google Search Console URL Inspection tool showing indexation status
URL-Prüfung in der Google Search Console zeigt den Indexierungsstatus und wie Googlebot die Seite gerendert hat. Quelle: Semrush Blog

JavaScript-Frameworks und SEO haben eine komplizierte Geschichte. Jahrelang lautete der Rat: „Nimm einfach serverseitiges Rendering“ — und das war es im Grunde. Heute ist das Bild differenzierter, aber auch besser greifbar.

Next.js mit dem App Router ist für die meisten Teams 2026 die beste Option. Server Components bedeuten, dass deine Seiten standardmäßig servergerendert sind, die Metadata API ist typgesichert und umfassend, und das Ökosystem ist reif. Wenn du im Vue-Ökosystem unterwegs bist, bietet dir Nuxt die gleichen Kernvorteile — nur mit leicht anderer API-Oberfläche.

Reine React-SPAs sollten nicht für öffentliche Seiten eingesetzt werden. Ich bin müde davon, React-SPAs auf Marketingseiten zu sehen. Es ist 2026. Wir sollten es besser wissen. Und daran wird sich nichts ändern — wenn überhaupt, macht der Aufstieg von KI-Crawlern, die kein JavaScript ausführen, das Ganze noch schwieriger, nicht leichter.

Eine Sache, bei der ich mir wirklich unsicher bin: die langfristige Entwicklung von Remix gegenüber Next.js in Bezug auf SEO. Remixes Philosophie „nur SSR, keine Caching-Schicht“ ist in ihrer Einfachheit verlockend. Wenn Edge Computing günstiger wird, schwächt sich das Argument für ISR (Remixes Mittelweg) ab. Ich würde 2027 nicht gegen Remix wetten. Aber heute hat Next.js mehr eingebaute SEO-Funktionen, ein größeres Ökosystem und bessere Dokumentation. Nutze, was dein Problem jetzt löst.

Wenn sich das nach viel Konfiguration anhört — ist es auch. Deshalb gibt es SEOJuice: Du wählst die Rendering-Strategie, wir automatisieren den Rest.


FAQ

Rendern Googles Suchmaschinen jetzt wirklich JavaScript?

Ja, aber mit Einschränkungen. Google nutzt den Web Rendering Service (ein evergreen Chromium), um JavaScript auszuführen. Das Rendering passiert im zweiten Durchlauf — nach dem initialen Crawl — und kann je nach Seite von Sekunden bis zu Tagen dauern. Bei etablierten Websites mit hohen Crawl-Budgets klappt es meistens schnell. Bei neuen oder wenig autoritativen Sites kann die Verzögerung deutlich sein. Und entscheidend: Googles Rendering ist nicht garantiert. Seiten, die von komplexen JavaScript-Interaktionen abhängen, Authentifizierung benötigen oder Rendering-Fehler haben, werden möglicherweise nie vollständig gerendert. Der sicherere Weg ist immer, im ersten Response vollständiges HTML auszuliefern.

Ist Nuxt für SEO besser oder schlechter als Next.js?

Wähle nach dem, ob euer Team Vue oder React schreibt — nicht nach Unterschieden bei SEO.

Wie behebe ich SEO für eine bestehende React-SPA, ohne alles neu zu schreiben?

Der schnellste Weg: Prerender.io oder einen ähnlichen Prerendering-Service als Middleware hinzufügen. Das unterbricht Crawler-Anfragen und liefert vorgerendertes HTML aus. Das dauert ungefähr eine Stunde bis zur Einrichtung und macht deinen Content sofort für Suchmaschinen sichtbar. Danach plane eine schrittweise Migration zu Next.js — der App Router kann parallel zu bestehenden Seiten laufen, sodass du Route für Route migrieren kannst, statt alles im Big-Bang umzuschreiben. Starte mit deinen Seiten mit dem höchsten Traffic.

SEOJuice
Stay visible everywhere
Get discovered across Google and AI platforms with research-based optimizations.
Works with any CMS
Automated Internal Links
On-Page SEO Optimizations
Get Started Free

no credit card required