Apogée Consult
Retour au blog
Mathieu Ponton
Mathieu PontonCo-Founder & ingénieur logiciel

Je suis Mathieu Ponton, Co-Founder & ingénieur logiciel chez Apogée Consult à Lyon. Ingénieur diplômé de Polytech Lyon (Informatique), j'ai fait trois ans en apprentissage, partagés entre la Métropole de Lyon (inclusion numérique avec Res'in et sobriété énergétique avec Écolyo) et Superwyze, une startup medtech (POCs, dont certains aujourd'hui industrialisés, et travail sur des codebases existantes). J'ai livré plus de 10 projets en production (web, mobile et IA / RAG) pour des PME, startups et organisations publiques.

SEO programmatique sur Next.js : comment générer 50 000 pages sans pénalité Google

  • seo-tech

Générer des dizaines de milliers de pages en Next.js est techniquement possible. Le faire sans déclencher une pénalité pour contenu dupliqué ou thin content demande une architecture précise.

SEO programmatique sur Next.js : comment générer 50 000 pages sans pénalité Google

Le SEO programmatique consiste à générer automatiquement un grand nombre de pages optimisées à partir d'une base de données structurée. L'idée est bonne : couvrir des requêtes longue traîne à l'échelle sans rédiger chaque page manuellement. Le problème est que les implémentations naïves produisent exactement ce que Google pénalise : du contenu mince, dupliqué, et sans valeur ajoutée différentielle.

Ce que Google sanctionne réellement

La pénalité pour "thin content" n'est pas déclenchée par le volume de pages. Elle est déclenchée par un ratio défavorable entre le nombre de pages indexées et les signaux de qualité que Google peut mesurer sur ces pages.

Les critères problématiques, d'après la documentation Google Search Central et les analyses post-HCU (Helpful Content Update) :

  • Pages dont le contenu principal varie uniquement par un paramètre de template (ville, catégorie) sans différence substantielle
  • Pages sans trafic, sans liens entrants, sans engagement utilisateur mesurable
  • Pages en contenu dupliqué pur, même texte, URL différente

La mécanique est progressive : Google commence par ne pas indexer ces pages, puis peut dévaluer l'ensemble du domaine si le ratio de contenu de faible qualité est trop élevé. Ce dernier point est souvent sous-estimé.

L'architecture Next.js pour 50 000 pages

Structure de données comme base

La première condition est d'avoir une base de données structurée avec suffisamment de dimensions pour différencier les pages de manière substantielle.

Exemple pour un annuaire de professionnels par ville et spécialité :

/avocats/lyon → liste + contenu spécifique Lyon
/avocats/lyon/droit-social → liste + contenu spécifique Lyon + droit social
/avocats/lyon/droit-social/jean-dupont → profil individuel

Chaque niveau de granularité doit apporter un contenu unique. Si les pages /avocats/lyon/droit-social et /avocats/marseille/droit-social ont le même texte introductif avec le nom de ville en substitution, c'est du contenu dupliqué.

Génération statique vs dynamique

Pour 50 000 pages, generateStaticParams avec revalidation ISR est la bonne approche. Tout générer en static au build serait trop long. Tout rendre en dynamique serait trop lent.

// app/[specialite]/[ville]/page.tsx
export async function generateStaticParams() {
  // Générer uniquement les combinaisons à fort volume de recherche
  const topCombinations = await db.query(`
    SELECT specialite, ville
    FROM search_volume
    WHERE monthly_searches > 100
    ORDER BY monthly_searches DESC
    LIMIT 5000
  `);
  
  return topCombinations.map((row) => ({
    specialite: row.specialite,
    ville: slugify(row.ville),
  }));
}

export const revalidate = 86400; // 24h ISR pour le reste

Les pages à fort volume de recherche sont statiques et ultra-rapides. Les pages longue traîne sont générées à la demande et mises en cache 24h. Google peut crawler les deux, la différence est invisible côté moteur.

Canonical et gestion du contenu dupliqué

Certaines combinaisons de paramètres produisent inévitablement des pages quasi-identiques. La règle : si deux URLs produisent un contenu identique à plus de 60%, une des deux doit pointer vers l'autre en canonical.

// app/[specialite]/[ville]/page.tsx
import type { Metadata } from "next";

export async function generateMetadata({ params }): Promise<Metadata> {
  const page = await getPageData(params);
  
  // Si c'est une page quasi-dupliquée, pointer vers la page canonique
  if (page.isCanonicalRedirect) {
    return {
      alternates: {
        canonical: page.canonicalUrl,
      },
    };
  }
  
  return {
    title: page.title,
    description: page.metaDescription,
    alternates: {
      canonical: `https://exemple.fr/${params.specialite}/${params.ville}`,
    },
  };
}

Quality signals : ce qui différencie vraiment les pages

Le contenu textuel seul ne suffit pas. Pour qu'une page programmatique passe le filtre HCU, elle doit inclure des signals de qualité mesurables :

Données uniques par page : avis vérifiés, tarifs réels, disponibilités, statistiques locales. Une page /avocats/lyon/droit-social qui affiche les 12 avocats avec leurs vraies notes, tarifs indicatifs, et disponibilités est substantiellement différente d'une page équivalente à Marseille.

Interactions mesurables : formulaire de contact, prise de rendez-vous, téléphone. Google peut inférer l'engagement depuis le taux de clics en SERP et le comportement post-clic.

Fraîcheur : un horodatage de dernière mise à jour crédible (et réel). Une page "mise à jour le 15 juin 2025" dont le contenu date de 2023 est un signal négatif.

Le sitemap à cette échelle

50 000 URLs ne tiennent pas dans un seul sitemap. Google limite à 50 000 URLs ou 50 Mo par fichier de sitemap. La solution standard est le sitemap index.

Nous y consacrons un article dédié (voir article 062), mais le principe : un sitemap-index.xml qui référence N fichiers sitemap-{n}.xml, chacun contenant au maximum 10 000 URLs avec leurs priorités et fréquences de mise à jour.

Ce qui ne fonctionne pas

Générer toutes les combinaisons possibles. Si vous avez 500 spécialités × 200 villes = 100 000 combinaisons, la plupart n'ont aucun volume de recherche. Google les trouvera, tentera de les indexer, et l'absence de trafic et d'engagement deviendra un signal négatif de masse. Filtrez dès la génération.

Utiliser des métadonnées génériques. Un <title> du type "Avocats à [Ville] | MonSite" est insuffisant. La balise title doit refléter le contenu réel de la page, "12 avocats droit social à Lyon, tarifs et avis vérifiés" est substantiellement meilleur.

Ignorer l'indexation réelle. Soumettez votre sitemap index à Google Search Console et monitorez le ratio "Pages demandées à l'indexation / Pages effectivement indexées". Un ratio inférieur à 30% est un signal que Google considère votre contenu de faible qualité.

La question qui reste ouverte après nos déploiements : quel est le seuil de différentiation minimal acceptable pour Google ? Les guidelines parlent de "contenu substantiellement unique" sans le définir quantitativement. L'empirisme reste la seule méthode fiable.

Disponible pour de nouveaux projets

Un projet à concrétiser ?
Parlons-en, sans engagement.

Un échange de 30 minutes pour cadrer votre besoin, qualifier la faisabilité et vous proposer une trajectoire claire.

1// kick-off : réponse sous 24h
2const project = await apogee.scope({
3 type: 'web | mobile | IA',
4 timeline: '6 à 16 semaines',
5 approach: 'sur-mesure'
6})
7// → cadrage offert
SEO programmatique Next.js : 50 000 pages sans pénalité | Apogée Consult