Warum Next.js für SEO besser ist als reines React
React hat ein fundamentales SEO-Problem: Es rendert standardmäßig im Browser (Client-Side Rendering, CSR). Das bedeutet: Wenn Google deine Seite crawlt, sieht es zunächst ein leeres — und muss den JavaScript-Code erst ausführen, um den Inhalt zu sehen.
Google kann JavaScript rendern — aber mit Einschränkungen:
Merksatz: „Googlebot kann JavaScript. Aber er ist langsam, ungeduldig und rendert in einer Warteschlange. Was er sofort lesen kann, indexiert er sofort."
Next.js löst dieses Problem durch Server-Side Rendering (SSR) und Static Site Generation (SSG): Der HTML-Code wird bereits auf dem Server oder zur Build-Zeit generiert und als vollständiges HTML an den Browser (und an Googlebot) ausgeliefert. Kein Warten auf JavaScript-Execution.
| Aspekt | Reines React (CSR) | Next.js (SSR/SSG) |
|--------|-------------------|-------------------|
| Erster HTML-Response | Leeres | Googlebot-Indexierung | Verzögert (JavaScript Rendering Queue) | Sofort | | Core Web Vitals (LCP) | Schlecht (JS muss erst laden) | Gut (HTML direkt da) | | Social Media Previews | Oft leer (kein SSR) | Korrekt (Meta-Tags im HTML) | | Time to First Byte | Schnell (nur statische Datei) | Schnell (SSG) / Mittel (SSR) | Next.js bietet vier Rendering-Strategien. Jede hat unterschiedliche SEO-Implikationen: Seiten werden zur Build-Zeit generiert. Das Ergebnis ist pures HTML, das vom CDN ausgeliefert wird. Perfekt für Content, der sich selten ändert. SEO-Vorteil: Schnellste Ladezeit (direkt vom CDN), beste Core Web Vitals, sofort crawlbar. Nachteil: Bei Inhaltsänderungen muss neu gebaut werden — oder ISR nutzen. Seiten werden bei jedem Request auf dem Server generiert. Sinnvoll für personalisierte oder häufig wechselnde Inhalte. SEO-Vorteil: Immer aktueller Inhalt, vollständiges HTML für Crawlers. Nachteil: Höhere Server-Last, langsamere Time to First Byte als SSG. Seiten werden statisch generiert, aber in definierten Intervallen im Hintergrund aktualisiert. Der Nutzer sieht die gecachte Version, während der Server die neue Version baut. SEO-Vorteil: CDN-Geschwindigkeit + aktuelle Inhalte. Perfekt für Blogs, Produktseiten, Landingpages. Inhalte werden erst im Browser gerendert. Für SEO-relevante Seiten nicht verwenden. Wann CSR OK ist: Dashboard-Bereiche hinter Login, interaktive Tools, User-spezifische Inhalte die nicht indexiert werden sollen. Merksatz: „SSG für alles was sich selten ändert. ISR für alles was sich regelmäßig ändert. SSR für alles was sich bei jedem Request ändert. CSR für alles was Google nie sehen soll." Next.js hat mit dem App Router eine elegante Metadata API eingeführt. Statische und dynamische Meta-Tags lassen sich direkt in der Page-Komponente definieren: Statische Metadata: Dynamische Metadata: Wichtig: Jede Seite braucht einen einzigartigen Next.js unterstützt seit Version 13.3 eine native Sitemap-Generierung: Die Sitemap wird automatisch unter Canonical URLs sind essenziell, um Duplicate Content zu vermeiden — besonders bei Seiten mit URL-Parametern (Filter, Sortierung, Paginierung). Regel: Jede indexierbare Seite braucht eine Canonical URL. Die Canonical zeigt immer auf die „Hauptversion" der Seite — ohne Tracking-Parameter, ohne Session-IDs. Structured Data hilft Google, den Inhalt deiner Seite zu verstehen — und ermöglicht Rich Snippets in den Suchergebnissen (FAQ-Dropdowns, How-To-Schritte, Bewertungssterne, Breadcrumbs). Die wichtigsten Schema-Typen für Content-Websites: | Schema-Typ | Wofür | Rich-Snippet-Effekt | |------------|-------|---------------------| | Article | Blog-Posts, Artikel | Datum, Autor in den SERPs | | FAQPage | FAQ-Sektionen | Expandierbare Fragen in Google | | HowTo | Anleitungen, Tutorials | Schritte als Liste in Google | | BreadcrumbList | Navigation / Breadcrumbs | Breadcrumb-Pfad in den SERPs | | LocalBusiness | Lokale Unternehmen | Knowledge Panel, Maps | | Organization | Unternehmensdaten | Logo, Social-Links im Panel | Merksatz: „Structured Data ist kein Ranking-Faktor. Aber es ist ein CTR-Faktor — und CTR beeinflusst Rankings indirekt." LCP misst, wie schnell das größte sichtbare Element geladen wird. Ziel: unter 2,5 Sekunden. Next.js Hebel: CLS misst visuelle Stabilität. Ziel: unter 0,1. Next.js Hebel: INP misst die Reaktionszeit auf Nutzer-Interaktionen. Ziel: unter 200ms. Next.js Hebel: | # | Fehler | Lösung | |---|--------|--------| | 1 | Keine Metadata API nutzen, leerer | 2 | Alle Seiten als CSR (Client Components) | Server Components als Default | | 3 | Keine Sitemap | | 4 | Fehlende Canonical URLs | | 5 | | 6 | Custom Fonts ohne | 7 | robots.txt vergessen | | 8 | JSON-LD fehlt | | 9 | Third-Party Scripts blockieren Rendering | | 10 | Kein Häufige Fragen FAQRendering-Strategien und ihre SEO-Auswirkungen
Static Site Generation (SSG) — der SEO-Champion
// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
const posts = await getAllPosts()
return posts.map((post) => ({ slug: post.slug }))
}
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return <article>{post.content}</article>
}Server-Side Rendering (SSR) — für dynamische Inhalte
// app/produkt/[id]/page.tsx
// In Next.js 14+ App Router ist SSR der Default für dynamische Routen
export default async function Produkt({ params }: { params: { id: string } }) {
const produkt = await getProdukt(params.id)
return <ProduktSeite data={produkt} />
}Incremental Static Regeneration (ISR) — das Beste aus beiden Welten
// app/blog/[slug]/page.tsx
export const revalidate = 3600 // Alle 60 Minuten revalidieren
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
return <article>{post.content}</article>
}Client-Side Rendering (CSR) — der SEO-Killer
Meta-Tags und Open Graph in Next.js richtig setzen
Die Metadata API (Next.js 14+ App Router)
// app/ueber-uns/page.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Über uns | while.chat',
description: 'Wir machen SEO, Marketing und Webentwicklung für KMU im DACH-Raum.',
openGraph: {
title: 'Über uns | while.chat',
description: 'SEO, Marketing und Webentwicklung für KMU.',
url: 'https://while.chat/ueber-uns',
type: 'website',
images: [{ url: 'https://while.chat/images/ueber-uns-og.jpg', width: 1200, height: 630 }],
},
twitter: {
card: 'summary_large_image',
},
alternates: {
canonical: 'https://while.chat/ueber-uns',
},
}// app/blog/[slug]/page.tsx
import type { Metadata } from 'next'
export async function generateMetadata({ params }: { params: { slug: string } }): Promise<Metadata> {
const post = await getPost(params.slug)
return {
title: `${post.title} | while.chat`,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
url: `https://while.chat/blog/${params.slug}`,
type: 'article',
publishedTime: post.publishedAt,
images: [{ url: post.ogImage }],
},
alternates: {
canonical: `https://while.chat/blog/${params.slug}`,
},
}
}title und eine einzigartige description. Die Metadata API sorgt automatisch dafür, dass diese ins des HTML gerendert werden — ohne manuelles -Management.Title-Tag Best Practices
Titel | BrandMeta-Description Best Practices
Technisches SEO in Next.js: Sitemap, Robots, Canonical
XML-Sitemap automatisch generieren
// app/sitemap.ts
import { MetadataRoute } from 'next'
export default async function sitemap(): MetadataRoute.Sitemap {
const posts = await getAllPosts()
const blogEntries = posts.map((post) => ({
url: `https://while.chat/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly' as const,
priority: 0.8,
}))
return [
{
url: 'https://while.chat',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1,
},
{
url: 'https://while.chat/ueber-uns',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.5,
},
...blogEntries,
]
}/sitemap.xml ausgeliefert. Bei großen Seiten mit 50.000+ URLs kannst du generateSitemaps() nutzen, um mehrere Sitemaps zu erzeugen.robots.txt konfigurieren
// app/robots.ts
import { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: {
userAgent: '*',
allow: '/',
disallow: ['/api/', '/admin/', '/dashboard/'],
},
sitemap: 'https://while.chat/sitemap.xml',
}
}Canonical URLs setzen
// In der Metadata API:
export const metadata: Metadata = {
alternates: {
canonical: 'https://while.chat/blog/next-js-seo',
},
}Structured Data (JSON-LD) in Next.js einbinden
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug)
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.excerpt,
author: { '@type': 'Organization', name: 'while.chat' },
datePublished: post.publishedAt,
dateModified: post.updatedAt,
image: post.ogImage,
mainEntityOfPage: `https://while.chat/blog/${params.slug}`,
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article>{post.content}</article>
</>
)
}
Core Web Vitals in Next.js optimieren
LCP (Largest Contentful Paint) — das Hauptbild schneller laden
next/image verwenden statt : Automatische Lazy-Loading, WebP/AVIF-Konvertierung, responsive Sizespriority-Prop für Above-the-Fold-Bilder setzen (deaktiviert Lazy Loading)next/font für Schriften: Eliminiert Layout Shift durch Font-Loadingimport Image from 'next/image'
// Hero-Bild: priority = true für sofortiges Laden
<Image
src="/hero.jpg"
alt="Next.js SEO Guide Hero"
width={1200}
height={630}
priority
sizes="100vw"
/>CLS (Cumulative Layout Shift) — Sprünge vermeiden
width und height bei allen Images definieren (reserviert Platz)next/font mit display: swap und adjustFontFallbackimport { Inter } from 'next/font/google'
const inter = Inter({
subsets: ['latin'],
display: 'swap', // Zeigt Fallback-Font bis Custom-Font geladen
adjustFontFallback: true // Minimiert Layout Shift beim Font-Swap
})INP (Interaction to Next Paint) — Interaktionen schnell machen
React.lazy() und Suspense splitten'use client' nur dort wo nötig — alles andere als Server Component belassennext/script und strategy="lazyOnload" ladenimport Script from 'next/script'
// Analytics erst nach vollständigem Laden
<Script
src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXX"
strategy="lazyOnload"
/>Die 10 häufigsten Next.js SEO-Fehler
| generateMetadata für jede Route |app/sitemap.ts anlegen |alternates.canonical in Metadata | statt next/image | Image-Component mit priority für ATF |next/font | next/font für Zero-CLS-Fonts |app/robots.ts anlegen | einbauen |next/script mit lazyOnload |alt-Text bei Bildern | Beschreibendes alt für jedes Image |app/sitemap.ts und app/robots.ts decken die Grundlagen ab. Für JSON-LD kann das Package next-seo oder schema-dts hilfreich sein, ist aber nicht zwingend nötig. Die meisten „SEO-Plugins" für Next.js wrappen nur die eingebauten Features.curl -A Googlebot URL im Terminal — prüfen ob HTML vollständig ausgeliefert wird.next/head für Meta-Tags und getStaticProps/getServerSideProps für SSG/SSR. Für neue Projekte: App Router ist die Zukunft.Quellen & Vertiefung