Next.js : soigner son SEO avec l’App Router
· 7 min de lecture
Métadonnées, Open Graph, sitemap, JSON-LD et images de partage : ce que l’App Router de Next.js permet de configurer pour le SEO, et ses pièges.
En bref
Pour bien apparaître sur Google, chaque page doit se présenter : un titre, un court résumé, une image de partage. Next.js permet de le faire page par page, sans outil en plus. L’article montre comment faire, et les erreurs à éviter.
Un mot technique vous échappe ? Le glossaire du développement web l’explique simplement.
L’App Router de Next.js permet de soigner son SEO sans aucune librairie : il suffit d’exporter des objets ou des fonctions depuis les bons fichiers. Voici ce que j’ai mis en place sur ce portfolio, et les pièges rencontrés en chemin.
Des métadonnées par page
Une page fixe exporte un objet metadata. Une page qui change, comme un article, exporte la fonction generateMetadata. Elle reçoit les paramètres de la route :
export async function generateMetadata(
props: PageProps<'/blog/[slug]'>
): Promise<Metadata> {
const { slug } = await props.params;
const article = getArticle(slug);
if (!article) {
return {};
}
return {
title: article.title,
description: article.excerpt,
alternates: { canonical: `/blog/${slug}` },
};
}Le piège de la fusion
Next.js fusionne les métadonnées du layout et de la page, mais de façon superficielle : une page qui définit openGraph remplace tout l’objet openGraph du layout, siteName et locale compris. Le plus simple est de regrouper ces valeurs communes dans un module et de les réinjecter dans chaque page.
Des longueurs qui comptent
- Un title de 50 à 60 caractères, mot-clé principal en tête : au-delà, Google le tronque.
- Une description de 120 à 160 caractères, qui résume la page et donne envie de cliquer.
- Un seul h1 par page, qui décrit vraiment son contenu.
- Des textes de lien courts et explicites plutôt que des cartes entières cliquables.
Un sitemap généré
Le fichier sitemap.ts crée le sitemap.xml au moment du build. Chaque nouvel article y apparaît tout seul :
export default function sitemap(): MetadataRoute.Sitemap {
return [
{ url: 'https://example.com', lastModified: new Date() },
...articles.map(article => ({
url: `https://example.com/blog/${article.slug}`,
lastModified: article.updated ?? article.date,
})),
];
}Ne pas tout indexer
Toutes les pages n’ont pas vocation à apparaître dans Google. Une page de tag qui ne liste qu’un seul article cible le même mot-clé que lui et lui fait concurrence. L’option robots la garde accessible aux visiteurs tout en la retirant de l’index, et follow laisse les moteurs suivre ses liens :
return {
title,
robots: { index: articles.length >= 2, follow: true },
};Des images de partage en JSX
Un fichier opengraph-image.tsx placé à côté d’une page génère son image Open Graph avec ImageResponse, à partir de JSX et de CSS. Chaque article obtient ainsi une vignette à son titre, sans logiciel de graphisme. La même convention, avec apple-icon.tsx, produit l’icône d’écran d’accueil iOS.
Les données structurées
Le JSON-LD s’injecte dans une balise script de type application/ld+json. Rendu par un Server Component (voir « React Server Components : ce qui change vraiment »), il n’ajoute aucun JavaScript côté client. La librairie schema-dts fournit les types de schema.org et évite les fautes de frappe dans les propriétés. Attention aux types qui ne servent plus : Google réserve désormais les résultats enrichis FAQ aux sites gouvernementaux et de santé, alors que BlogPosting et BreadcrumbList restent utiles.
Avec Next.js, le SEO technique se règle surtout en plaçant les bons fichiers. L’essentiel reste à faire soi-même : un contenu utile et une page rapide (voir « INP : optimiser la réactivité perçue de son site »).