Adios
BlogSEO avec Next.js

SEO avec Next.js

SEO Next.js pour la production : guide complet

Configurez le SEO Next.js avec rendu serveur, métadonnées, URL canoniques, sitemaps, JSON-LD, Core Web Vitals et contrôles de mise en production.

Équipe AdiosMise à jour 17 juillet 202613 min de lecture

Le SEO Next.js en production repose sur un contrat de route : chaque URL publique exige une réponse utile, un contenu rendu sur le serveur, des métadonnées cohérentes, une règle d’indexabilité claire et un contrôle de mise en production prouvant que ces signaux y sont présents.

Donner un rôle précis à chaque route indexable

Next.js fournit des API de rendu et de métadonnées sans décider quelles pages méritent le trafic de recherche. Définissez pour chaque route publique le lecteur, la requête, la réponse, l’URL canonique et l’action suivante. Cela distingue une page utile d’un doublon techniquement indexable.

Associez une URL durable à chaque intention distincte. Présentation du produit, guide d’implémentation, tarifs et référence API peuvent parler du même produit en répondant à des besoins différents. Deux pages répétant la même réponse sous des titres différents affaiblissent le choix du lecteur et ajoutent de la maintenance.

Notez la décision dans un inventaire de routes avant d’écrire les métadonnées. Incluez le modèle de route, la source, le mode de rendu, la règle canonique, l’indexabilité et l’événement de mise à jour. Cet inventaire devient le contrat commun du contenu, de l’ingénierie et des contrôles de mise en production.

  • —Indexez les pages qui apportent une réponse complète et autonome.
  • —Gardez hors de l’index les pages privées, vides, de recherche interne, d’aperçu et les filtres de faible valeur.
  • —Pointez les liens internes vers l’URL canonique plutôt que compter sur une balise pour réparer une navigation incohérente.
  • —Associez les mises à jour du contenu à de vrais événements, comme un changement produit, une révision éditoriale ou une mise à jour des stocks.

Mettre la réponse principale dans la première réponse HTML

Les pages et layouts App Router sont des Server Components par défaut. Utilisez-les pour le titre, l’introduction, le texte, les informations produit, le fil d’Ariane et les liens contextuels. La réponse initiale contient alors la réponse principale sans attendre une requête navigateur.

Un Client Component convient si la fonctionnalité nécessite un état, un gestionnaire d’événement, un hook de cycle de vie ou une API navigateur. Gardez cette limite près de l’interaction. Un calculateur de prix peut être interactif sans transformer toute la page produit en structure rendue côté client.

Le rendu est aussi un choix de fraîcheur. La génération statique convient au contenu modifié avec une version ; le rendu serveur aux données publiques propres à la requête ; le rendu en cache aux données partagées avec un événement d’invalidation défini. Choisissez le modèle le plus ciblé qui garde la réponse exacte, sans rendre toute une route dynamique pour une petite commande.

Construire une hiérarchie de métadonnées adaptée aux vraies routes

Définissez metadataBase, un modèle de titre, la description par défaut et les champs sociaux communs dans le layout racine. Remplacez les valeurs au niveau le plus précis du layout ou de la page concernée. Les routes statiques exportent metadata ; celles alimentées par des données utilisent generateMetadata. Les deux API sont réservées au serveur.

Traitez les métadonnées imbriquées comme des objets complets sur la route qui les remplace. Next.js fusionne les métadonnées de la racine vers la page, mais remplace les champs imbriqués sans fusion profonde. Un objet openGraph de page qui ne fournit qu’un nouveau titre peut perdre une image héritée.

Les versions actuelles de Next.js peuvent diffuser les métadonnées en streaming pour les robots exécutant JavaScript tout en les gardant bloquantes pour ceux limités au HTML. Cela améliore les délais de réponse sans rendre inoffensives des requêtes de métadonnées lentes ou peu fiables. Réutilisez les données résolues de la page, gérez explicitement les entités absentes et testez les routes réussies comme manquantes.

app/layout.tsx and app/products/[slug]/page.tsx

// app/layout.tsx
import type { Metadata } from "next";

export const metadata: Metadata = {
  metadataBase: new URL("https://www.example.com"),
  title: { default: "Acme", template: "%s | Acme" },
  description: "Tools for production engineering teams.",
  openGraph: {
    siteName: "Acme",
    images: [{ url: "/og-default.png", width: 1200, height: 630 }],
  },
};

// app/products/[slug]/page.tsx
export async function generateMetadata({ params }): Promise<Metadata> {
  const { slug } = await params;
  const product = await getProduct(slug);

  if (!product) return { title: "Product not found", robots: { index: false } };

  return {
    title: product.name,
    description: product.summary,
    alternates: { canonical: "/products/" + product.slug },
    openGraph: {
      title: product.name,
      description: product.summary,
      images: product.images.map((image) => ({ url: image.url })),
    },
  };
}

Traiter les URL canoniques, redirections et robots comme une seule politique

L’URL canonique désigne la version préférée d’un contenu dupliqué ou très similaire. Rendez cette préférence cohérente dans les redirections, annotations canoniques, liens internes et sitemap. Google considère les redirections et rel=canonical comme des signaux forts, et la présence dans le sitemap comme plus faible ; des signaux alignés sont plus faciles à interpréter qu’une balise corrective entourée de contradictions.

Définissez une seule fois le protocole, l’hôte, les slashs finaux, la casse et les paramètres approuvés. Redirigez les variantes d’hôte et de chemin qui ne doivent pas rester accessibles. Une URL canonique pointant vers la page elle-même peut aider à garder les URL générées cohérentes.

Utilisez les métadonnées robots pour l’indexabilité et robots.txt pour l’exploration. Aucun ne protège le contenu privé. L’autorisation doit rejeter toute requête non authentifiée, quels que soient ses en-têtes de robot. N’envoyez pas noindex d’abord pour tenter de le retirer dans le navigateur : Google peut s’arrêter avant le rendu du changement JavaScript.

A page-level canonical and indexability rule

import type { Metadata } from "next";

export const metadata: Metadata = {
  alternates: { canonical: "/guides/nextjs-seo" },
  robots: { index: true, follow: true },
};

Générer les fichiers des robots depuis le contenu publié

Générez sitemap.ts et robots.ts depuis la même source que le contenu public. Le sitemap doit contenir les URL absolues canoniques que vous souhaitez faire découvrir. Excluez les espaces de compte, aperçus, recherches internes, chemins redirigés et combinaisons de paramètres sans valeur propre.

Utilisez lastModified seulement pour une mise à jour importante du contenu principal, des données structurées ou des liens. Google ignore priority et changefreq dans les sitemaps : ils ne corrigent pas une liste d’URL périmée ou bruitée. Pour un grand catalogue, séparez les sitemaps par famille si cela clarifie la génération, la supervision ou les responsabilités.

Traitez robots.txt comme un guide d’exploration, pas comme un moyen de cacher. Une URL interdite peut être connue par des liens externes et son blocage peut empêcher un robot de voir noindex. Retirez les routes sensibles de la découverte publique et contrôlez leur accès dans l’application.

  • —Récupérez le sitemap de production et confirmez une réponse XML avec statut de succès.
  • —Échantillonnez les URL de chaque famille de contenu et vérifiez qu’elles se résolvent sans redirection.
  • —Comparez le nombre d’URL du sitemap aux enregistrements publiés et canoniques de la source de contenu.
  • —Signalez les URL générées qui sont noindex, absentes, redirigées ou canoniques ailleurs.

app/sitemap.ts

import type { MetadataRoute } from "next";

const siteUrl = "https://www.example.com";

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await getPublishedPosts();

  return posts
    .filter((post) => post.indexable)
    .map((post) => ({
      url: new URL("/blog/" + post.slug, siteUrl).toString(),
      lastModified: post.updatedAt,
    }));
}

Décrire les entités visibles avec un JSON-LD exact

Les données structurées nomment les entités déjà présentées sur la page. Choisissez le type selon sa fonction réelle : Article pour un article éditorial, Product pour un article achetable, BreadcrumbList pour la hiérarchie ou SoftwareApplication pour un vrai logiciel. Ajouter un type ne change pas la nature de la page.

Incluez les propriétés requises par la fonctionnalité de recherche visée et alignez les valeurs sur le contenu visible. N’inventez pas d’avis, notes, prix, disponibilité, auteurs ou dates de mise à jour. Un balisage complet et exact vaut mieux qu’un grand objet composé de champs que la page ne justifie pas.

Rendez le JSON-LD sur le serveur et nettoyez la valeur sérialisée si elle contient des données que vous ne contrôlez pas entièrement. Validez l’URL déployée avec un outil de données structurées, puis examinez le script. Un analyseur qui réussit confirme la syntaxe, pas la fidélité, l’actualité ou l’éligibilité à un résultat enrichi.

A server-rendered Article script

const article = {
  "@context": "https://schema.org",
  "@type": "Article",
  headline: post.title,
  description: post.excerpt,
  datePublished: post.publishedAt,
  dateModified: post.updatedAt,
  mainEntityOfPage: new URL("/blog/" + post.slug, siteUrl).toString(),
  author: { "@type": "Organization", name: "Acme" },
};

const json = JSON.stringify(article).replaceAll("<", "\u003c");

return <script type="application/ld+json">{json}</script>;

Préserver l’expérience de page au niveau des composants

Le SEO échoue si le résultat est indexable mais pénible à utiliser. Limitez le périmètre client, réservez l’espace des images, chargez seulement les polices utiles et donnez aux zones secondaires lentes des contenus d’attente pertinents. Le premier écran doit apporter la réponse principale, plutôt qu’une structure vide ou instable pendant le chargement des ressources.

Mesurez des routes représentatives en production, plutôt qu’une seule page d’accueil soignée. Largest Contentful Paint mesure le chargement, Interaction to Next Paint la réactivité et Cumulative Layout Shift la stabilité visuelle. Évaluez le 75e percentile des visites réelles lorsque les données sont disponibles, puis reproduisez une régression précise en laboratoire.

Lorsqu’une route ralentit, cherchez la cause avant de supprimer du contenu utile. Causes fréquentes : un périmètre Client Component élargi, une requête bloquante, un script tiers non limité, une image principale trop lourde ou des polices qui retardent le texte. La correction doit préserver le rôle de la page.

  • —Mesurez au moins un article, une page de liste et une page de détail alimentée par des données.
  • —Notez séparément LCP, INP et CLS au lieu de les réduire à un seul score.
  • —Comparez les visites directes et la navigation client entre les routes.
  • —Retestez après le déploiement : CDN, environnement d’exécution et services tiers influencent le résultat en production.

Effectuer un contrôle SEO Next.js de mise en production en 15 minutes

La configuration SEO ne se termine pas lorsque le code semble correct. Compilez l’application de production, démarrez l’environnement prévu au déploiement et vérifiez l’URL candidate avant son association au domaine canonique. Une requête de métadonnées peut casser la compilation, une redirection supprimer une section et une route renvoyer une page introuvable soignée avec le mauvais statut.

Testez une page connue, une redirection, une page absente et une route dynamique représentative. Examinez la première réponse HTML pour le titre, la description, l’URL canonique, robots, le H1, la réponse d’introduction, les données structurées et les liens contextuels. Récupérez séparément robots.txt et sitemap.xml, puis comparez leurs URL à l’inventaire des routes.

Enregistrez les contrôles avec la version plutôt que compter sur la mémoire. Si une assertion critique de SEO échoue, gardez la version opérationnelle en ligne, corrigez la candidate et relancez les mêmes contrôles. Le résultat utile est une route de production dont la réponse respecte la politique approuvée.

  • —Confirmez que la requête principale et le résultat attendu par le lecteur correspondent encore à la page visible.
  • —Confirmez que la réponse principale et les liens explorables existent dans la première réponse HTML.
  • —Confirmez qu’un titre, une description, une URL canonique, une règle robots et un H1 décrivent la même page.
  • —Confirmez que les données structurées correspondent aux faits visibles et sont analysables sur l’URL déployée.
  • —Confirmez que les URL du sitemap sont canoniques, indexables, opérationnelles et datées de façon pertinente.
  • —Confirmez que les routes représentatives respectent le budget de performance de production de l’équipe.

A small production smoke test

npm run build
npm run start

curl -I https://preview.example.com/guides/nextjs-seo
curl -I https://preview.example.com/old-guide
curl -I https://preview.example.com/not-a-real-page
curl -s https://preview.example.com/guides/nextjs-seo | grep -E "<title|canonical|robots|application/ld\+json"
curl -I https://preview.example.com/robots.txt
curl -I https://preview.example.com/sitemap.xml
Tous les articles