Next.js SEO: Ihre App vollständig crawlbar und indexierbar machen
Sie bauen eine React-App, deployen sie und sehen zu, wie die Analytics flach
bleiben. Googles Crawler treffen auf Ihre Seiten, sehen ein leeres
<div id="root"></div> und ziehen weiter. Ihre Inhalte werden nie indexiert.
Next.js löst das, indem es vollständiges HTML auf dem Server rendert, bevor irgendetwas den Browser erreicht. Aber Server-Rendering allein reicht nicht - Sie brauchen korrekte Metadaten, strukturierte Daten und Performance, um tatsächlich zu ranken.
Zuerst: prüfen, was der Crawler bekommt
Bevor Sie irgendetwas ändern, sehen Sie sich die Serverantwort an, nicht das gerenderte DOM:
curl -s https://ihre-seite.de/produkt/x | grep -c "Produktbeschreibung"
Steht Ihr Inhalt nicht in dieser Ausgabe, hängt Ihre Indexierung davon ab, ob Google Ihr JavaScript rendert - was es tut, aber verzögert und ohne Garantie. Das ist die einzige Diagnose, die zählt, und die meisten überspringen sie.
Rendering-Strategien
SSR - bei jedem Request auf dem Server gerendert. Für Seiten, die pro Nutzer oder pro Minute anders aussehen: Suchergebnisse, Warenkorb, Kontostände.
SSG - zur Build-Zeit erzeugt. Schnellstmöglich, und für alles richtig, was sich selten ändert: Blogbeiträge, Landingpages, Dokumentation.
ISR - statisch erzeugt, im Hintergrund nach Ablauf neu gebaut. Der Kompromiss für große Produktkataloge, die sich täglich ändern, aber nicht pro Request.
Client-seitig - für SEO tot. Verwenden Sie es hinter dem Login, wo Indexierung ohnehin nicht erwünscht ist.
Die Faustregel: Statisch, wo es geht. ISR, wo statisch nicht reicht. SSR nur, wenn der Inhalt wirklich pro Request anders ist.
Metadata API
Im App Router brauchen Sie kein Zusatzpaket. Metadaten werden pro Route exportiert:
export const metadata: Metadata = {
metadataBase: new URL('https://ihre-seite.de'),
title: 'Seitentitel',
description: 'Beschreibung, die zum Klick einlädt.',
alternates: { canonical: '/produkt/x' },
openGraph: {
type: 'website',
url: 'https://ihre-seite.de/produkt/x',
images: [{ url: '/og/produkt-x.png', width: 1200, height: 630 }],
},
}
Für dynamische Routen generateMetadata, das dieselben Daten holen darf wie
die Seite - Next dedupliziert den Aufruf:
export async function generateMetadata({ params }): Promise<Metadata> {
const { slug } = await params
const produkt = await getProdukt(slug)
if (!produkt) return {}
return {
title: `${produkt.name} kaufen`,
description: produkt.kurzbeschreibung,
alternates: { canonical: `/produkt/${slug}` },
}
}
Beachten Sie: In Next 15 und neuer ist params ein Promise und muss
abgewartet werden.
Brauchen Sie noch next-seo?
Kurz: im App Router nein. next-seo wurde für den Pages Router gebaut, wo
Metadaten über next/head liefen. Die Metadata API deckt Titles, Descriptions,
Canonicals, OpenGraph, Twitter Cards und alternates.languages für hreflang
nativ ab.
Wenn Sie noch auf dem Pages Router sind, bleibt next-seo sinnvoll. Bei einer
Migration entfernen Sie es zusammen mit next/head.
Sitemap und robots
Beide als Dateikonventionen, nicht als API-Routen:
// app/sitemap.ts
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const produkte = await getAlleProdukte()
return produkte.map((p) => ({
url: `https://ihre-seite.de/produkt/${p.slug}`,
lastModified: p.aktualisiertAm,
}))
}
Ein Hinweis, der mehr Websites betrifft als man denkt: Setzen Sie
lastModified nicht auf new Date(). Dann behauptet jede URL bei jedem
Abruf, sie habe sich heute geändert, und Google lernt, Ihr lastmod
insgesamt zu ignorieren. Lassen Sie das Feld weg, wenn Sie kein echtes Datum
haben.
Strukturierte Daten
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schema) }}
/>
JSON.stringify ist wichtig. Ein von Hand zusammengesetzter JSON-String bricht
beim ersten Apostroph in einer Beschreibung, und wenn Sie versehentlich ein
React-Element hineinreichen, gibt er [object Object] aus - stillschweigend,
und deshalb bleibt es kaputt.
Core Web Vitals
LCP - next/image mit priority für das Bild über der Falz, Schriften
über next/font selbst hosten statt sie von fremden Servern zu laden.
CLS - immer Breite und Höhe angeben, Platz für Banner reservieren, keine Layoutverschiebung durch nachladende Schriften.
INP - Client-Bundles klein halten. Prüfen Sie, wie viele Ihrer Komponenten
'use client' tragen, obwohl sie es nicht brauchen; das ist in App-Router-
Projekten der häufigste Grund für zu viel JavaScript.
Die kurze Checkliste
- Inhalt steht in der Serverantwort, per
curlgeprüft - Canonical auf jeder Route
metadataBasegesetzt, sonst sind OG-URLs relativ- Sitemap ohne erfundenes
lastmod - JSON-LD über
JSON.stringify, validiert im Rich Results Test hreflangnur für Sprachen, die die Seite tatsächlich hat- Bilder mit
next/image, Schriften mitnext/font
Wenn Sie eine Next.js-Seite haben, die gecrawlt aber nicht indexiert wird - das ist die Diagnose, die ich für Agenturen und Produktteams mache, samt der Umsetzung danach.