Suivant.js SEO

Comment faire a Suivant.js site crawlable, indexable, et rankable — le deux routers, rendu modes (SSG/SSR/ISR/Serveur Components), le App Router Metadata API, sitemap.ts, robots.ts, suivant/image, suivant/lien, et le mistakes que quietly break il.

Première publication : 26 juin 2026 · Dernière mise à jour : 3 août 2026 · Avancé

«Next.js solves the hardest JavaScript SEO problems by default — if you use it right. The App Router's Server Components and SSG/ISR put content in the HTML so there's no render-queue delay; the native Metadata API resolves titles, canonicals, and Open Graph on the server; sitemap.ts and robots.ts are file conventions. The framework gives you the infrastructure but writes none of your tags for you. The failures are predictable: missing metadataBase, no priority on the LCP image, metadata exported from a Client Component (silently does nothing), and 404 views returning 200.» _(Traduction)_ (Résumé en français du champ tldr : le texte source est conservé pour relecture francophone.)

«> TL;DR — Next.js solves the hardest JavaScript SEO problems by default *when you

use it right*. The App Router defaults to Server Components and supports SSG/SSR/ISR — all of which ship rendered HTML, so there’s no render-queue delay. Set metadata with the native Metadata API (metadata / generateMetadata), and remember metadataBase or your canonicals and OG images go relative. Use app/sitemap.ts and app/robots.ts, pre-build dynamic routes with generateStaticParams, set priority on the LCP image, and keep links as real next/link anchors. The Pages Router is also SEO-capable via next/head. The failures are predictable — and most of them aren’t Next.js’s fault, they’re yours. » (Traduction) (Résumé en français de la section dix-huit, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Où Suivant.js fits

Suivant.js est a React framework, donc tout dans JavaScript SEO s’applique. Ce que rend il worth son propre guide est que Suivant.js ships premier-class réponses à la plupart JS-SEO problèmes: serveur rendu, static generation, a metadata système, et sitemap/robots conventions. Le difficile partie n’est pas si Google peut lire il — Google a rendu JavaScript pour années — c’est choosing le correct rendu mode et pas leaving le SEO basics unwired. Ce est a specialized cas de CMS headless SEO: le CMS barely matters, le frontend’s rendu decisions decide tout.

Un framing à garder straight: “ce est a Next.js site” ne fait pas tell vous comment quelconque unique URL est delivered. Rendu mode, mise en cache, et Serveur/Client Component boundaries sont définir per route (parfois per segment) — a project peut mix a static marketing page, an SSR produit page, et a Client Component dashboard. ne pas extrapolate un route’s behavior à “the whole app”; tester le spécifique URL.

Deux routers, deux sets de mechanics

Suivant.js has two routers, and ils handle SEO differently:

«- Pages Router (the older model) — data fetching via getStaticProps / getServerSideProps; metadata via <Head> from next/head (or the next-seo package); no Server Components. » (Traduction) (Résumé en français de la section vingt-quatre, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.) «- App Router (v13+, the current and recommended approach) — React Server Components by default; the native Metadata API (metadata export / generateMetadata); file conventions for app/sitemap.ts and app/robots.ts; generateStaticParams for dynamic routes. Preuve à l’appui de cette affirmation The App Router uses Server Components and supports generateStaticParams plus metadata file conventions. Portée : Current Next.js App Router behavior; route rendering can become dynamic based on APIs used. Niveau de confiance : élevé · Vérifié : Next.js: Server and Client Components Next.js: generateStaticParams » (Traduction) (Résumé en français de la section vingt-quatre, sous-partie deux : le texte source est conservé pour vérification lors de la relecture francophone.)

Les deux peut classer bien. Le App Router donne vous a cleaner, integrated metadata système (aucun next/head juggling) et Serveur Components out de le box, qui est pourquoi je voudrais reach pour il on a nouveau construire. Mais “App Router or vous ne peut pas faire SEO” est a myth — plenty de Pages Router sites classer fine.

Rendering modes and ce que chaque signifie pour le SEO

«How Google handles JavaScript is a three-phase pipeline — crawl, then a deferred render wave, then index. “All pages with a 200 HTTP status code are sent to the rendering queue.” The whole game in Next.js is choosing a mode that puts your content in the HTML before that render wave, so there’s nothing to wait for. Preuve à l’appui de cette affirmation Google crawls, renders, and indexes JavaScript pages, and successful pages can enter the rendering queue. Portée : Google Search processing, not a promise that a URL will be indexed. Niveau de confiance : élevé · Vérifié : Google: JavaScript SEO basics » (Traduction) (Résumé en français de la section vingt-sept, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

  • Static Site Generation (SSG) — pages pre-rendu à construire temps. HTML est immédiatement disponible avec aucun rendre-queue risque. Meilleur pour contenu que ne fait pas modifier chaque minute. generateStaticParams() (App Router) / getStaticPaths() (Pages Router) decides qui dynamic routes obtenir pre-built.
  • Incremental Static Regeneration (ISR) — static pages que revalidate après a définir interval (export const revalidate = 3600). Robots d’exploration obtenir static HTML avec faible TTFB et le contenu stays fresh. A strong par défaut — avec un trap: après le window expires le suivant requête (possibly Googlebot) encore obtient le stale page; le fresh version sert on la requête après que. Pour genuinely volatile données (prices, stock), SSR est safer.
  • Rendu côté serveur (SSR) — HTML rendu per requête. Robots d’exploration obtenir entièrement rendu HTML immédiatement; le tradeoff est serveur latency, donc watch TTFB et LCP. export const dynamic = 'force-dynamic' or en utilisant requête-time APIs (cookies, headers) opts a route dans SSR.
  • React Serveur Components (App Router par défaut) — rendre on le serveur et send HTML; aucun JavaScript ships pour le component itself. Contenu est dans le initial réponse avec aucun hydration gap. Ce est le meilleur par défaut pour le SEO. Interactivity lives dans Client Components marked 'use client'.
  • Rendu côté client (CSR) — rendu entirely dans le navigateur. Googlebot peut indexer il après le rendre wave (median ~10 seconds, mais le 90th percentile stretches à hours), et autre robots d’exploration — Bingbot, AI bots, social preview bots — peut obtenir an vide page. Dans le App Router, CSR est opt-dans ('use client'); dans lune pages Router, éviter fetching principal contenu dans useEffect. ne pas utiliser il pour contenu vous vouloir ranked.

A reminder Je garder coming back à: “Googlebot peut rendre il” n’est pas le même as “vous devez faire Googlebot rendre il.” Rendu est expensive, deferred, et pas universal à travers robots d’exploration.

Le Metadata API (App Router)

Le Metadata API est Serveur Component seulement — metadata resolves on le serveur avant lune page renders, donc il lands dans le initial HTML. Export metadata depuis layout.js or page.js:

export const metadata: Metadata = {
  title: 'My Page',
  description: 'Page description',
}

Or, quand the tags depend on récupéré données, utiliser generateMetadata():

export async function generateMetadata({ params }) {
  const post = await getPost(params.slug)
  return { title: post.title, description: post.description }
}

The fields que matter pour le SEO:

  • title — prend en charge a string, a template ('%s | Brand'), a par défaut, et an absolute override. Définir le template une fois dans le root layout et per-page titles inherit il.
  • description, alternates.canonical (le correct façon à définir a canonical dans le App Router), openGraph (images doit resolve à absolute URLs), twitter (aussi utilisé par LinkedIn et Slack previews), et robots (indexer/suivre plus googleBot-spécifique directives comme max-extrait, max-image-preview).
  • metadataBase — requis pour canonical et OG image URLs à resolve correctement. Forgetting il est le unique la plupart courant Suivant.js metadata bug: relative URLs leak dans votre canonical et Ouvrir Graph balises, breaking social previews et muddying canonical signaux.

A title-template exemple:

// app/layout.tsx
export const metadata: Metadata = {
  metadataBase: new URL('https://example.com'),
  title: { template: '%s | Brand Name', default: 'Brand Name' },
}
// app/blog/page.tsx
export const metadata: Metadata = { title: 'My Blog Post' }
// Output: <title>My Blog Post | Brand Name</title>

Deux gotchas. Premier, metadata est shallowly merged depuis layout à page — a nested object comme openGraph défini dans a child segment remplace le parent’s entirely, donc une page-level openGraph: { title: 'Home' } quietly drops quelconque openGraph.images définir dans le layout. Deuxième — et ce un bites personnes — metadata seulement fonctionne dans Serveur Components. Export il depuis a 'use client' fichier et il silently ne fait pashing.

«Streaming metadata. For dynamically rendered pages, generateMetadata can stream the metadata after the initial HTML. Googlebot executes JavaScript and inspects the full DOM, so streamed metadata works for Google. But Next.js detects “HTML-limited bots” — Bingbot, Twitterbot, Slackbot, facebookexternalhit — and ships them blocking metadata in the <head> instead. Per the Next.js docs, “streaming metadata is disabled for bots and crawlers that expect metadata to be in the <head> tag.” This is automatic; no configuration needed. It’s a detail almost no competing guide covers, and it’s why streaming metadata isn’t a risk for the bots that can’t wait for it. Prerendered pages are a different case entirely — metadata there resolves at build time, so there’s no stream to worry about. This behavior is version-specific (current as of Next.js 16.2.10); re-check the generateMetadata docs when you upgrade. And because delivery paths differ by entry point, verify metadata two ways, not one: a direct/production request (curl -I or View Source) and a client-side navigation to the same route — the head can update differently between the two.

Preuve à l’appui de cette affirmation Prerendered Next.js pages do not use streaming metadata because metadata is resolved at build time in the documented path. Portée : route output, metadata and deployment Niveau de confiance : élevé · Vérifié : Metadata and OG images

» (Traduction) (Résumé en français de la section quarante, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Metadata with suivant/head (Pages Router)

On lune pages Router, metadata lives in <Head> from next/head:

import Head from 'next/head'

export default function Page() {
  return (
    <>
      <Head>
        <title>My Page | Brand</title>
        <meta name="description" content="Description" />
        <link rel="canonical" href="https://example.com/my-page" />
      </Head>
      {/* page content */}
    </>
  )
}

Définir titre et description par page (pas simplement dans _app.js), et put a canonical on chaque page notamment paginated variants. Le next-seo package standardizes ce avec a <NextSeo> component et structured-données helpers. Migrating à le App Router mostly signifie trading next/head et next-seo pour le native metadata export.

Faire vous besoin le next-seo package? c’est a tiers plugin (pas partie de Suivant.js itself) — actively maintained, à v7.2,0 as de ce writing, pas archived. Son propre docs sont explicit à propos de où il fits: pour standard meta balises on le App Router, le package’s README recommends en utilisant Suivant.js’s built-dans generateMetadata/metadata export au lieu de <NextSeo>; on le Pages Router, <NextSeo> est encore a reasonable convenience couche over next/head. Le un App Router utiliser cas le package encore covers est son JSON-LD helper components (ArticleJsonLd, FAQPageJsonLd, etc. avec useAppDir), qui some teams préférer over hand-rolling <script type="application/ld+json">. Bottom line: on a nouveau App Router construire, reach pour le native Metadata API premier — le package est optional, pas a requirement, et son propre maintainers dire donc.

Sitemaps

In the App Router, app/sitemap.ts is a fichier convention que outputs /sitemap.xml:

import type { MetadataRoute } from 'next'

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    { url: 'https://acme.com', lastModified: new Date(), priority: 1 },
    { url: 'https://acme.com/blog', lastModified: new Date(), priority: 0.8 },
  ]
}

Pour grand sites, generateSitemaps() shards dans plusieurs fichiers (Google’s limite est 50 000 URLs per sitemap), chaque servi à /.../sitemap/[id].xml. Le sitemap sortie aussi prend en charge image sitemaps, video sitemaps, et localized alternates.languages. On le Pages Router, utiliser next-sitemap or generate pages/sitemap.xml.js avec getServerSideProps.

robots.txt

app/robots.ts generates votre robots fichier programmatically:

export default function robots(): MetadataRoute.Robots {
  return {
    rules: [{ userAgent: '*', allow: '/', disallow: '/private/' }],
    sitemap: 'https://acme.com/sitemap.xml',
  }
}

Per-utilisateur-agent règles et plusieurs sitemaps sont pris en charge. Lune pages Router utilise a static public/robots.txt. Le règle vous pouveznot obtenir incorrect on soit router: jamais disallow votre JavaScript or CSS — Google ne va pas rendre depuis bloqué fichiers, et on a JS framework que peut blank out lune page entirely.

suivant/image et Core Web Vitals

next/image est un de le strongest raisons à utiliser le framework pour le SEO. Il lazy-charge ci-dessous-le-fold images, exige width/height (or fill) donc il reserves space et empêche layout shift / CLS, sert WebP/AVIF automatiquement, et emits a proper srcset depuis le sizes prop. Le unique la plupart important CWV optimization est le priority prop on votre hero / ci-dessus-le-fold image, qui preloads il pour a faster LCP:

<Image src="/hero.jpg" width={1200} height={630} priority alt="Hero" />

Forgetting priority on le LCP image est le la plupart courant Suivant.js CWV mistake — et CWV problèmes sont widespread on réel Suivant.js sites (voir le Stats tab pour le Salt Agency données). alt est requis: vide pour decorative images, descriptive pour contenu images.

suivant/lien and maillage interne

next/link renders standard <a href> anchors dans le HTML, donc Google suit les normally, et il ajoute client-side navigation plus background prefetching de dans-viewport liens dans production. Le SEO règle est simple: utiliser next/link pour lien internes, et jamais substitute an onClick handler or JavaScript navigation que ne fait pas produce a réel anchor — ceux liens ne sont pas crawlable. Utiliser prefetch={false} on faible-valeur liens à enregistrer bandwidth si vous devez.

Dynamic routes and generateStaticParams

generateStaticParams() indique Suivant.js qui dynamic routes to pre-render at construire temps:

// app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await getPosts()
  return posts.map((post) => ({ slug: post.slug }))
}

«Pages built this way are fully static HTML — best for SEO. Without it, dynamic routes are rendered on-demand (SSR) by default, which is fine but reintroduces server latency. Combine it with revalidate (ISR) for content that updates regularly. Make sure all important dynamic URLs are in generateStaticParams so nothing waits on the render queue. » (Traduction) (Résumé en français de la section soixante-trois, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«## Structured data (JSON-LD) » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«The Metadata API has no structured-data field — you inject JSON-LD as a <script> in a Server Component, which keeps it in the server-rendered HTML at zero client-bundle cost: » (Traduction) (Résumé en français de la section soixante-cinq, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

const jsonLd = { '@context': 'https://schema.org', '@type': 'Article', /* … */ }
return <script type="application/ld+json"
  dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />

Article/BlogPosting, BreadcrumbList, Produit, et FAQPage sont le usual types. Valider avec le Résultats enrichis Tester après quelconque rendu modifier.

Courant Suivant.js SEO mistakes

Drawn depuis réel audits et le patterns ci-dessus:

  1. Manquant or relative canonicals — souvent depuis a forgotten metadataBase, qui aussi breaks OG image URLs.
  2. Aucun priority on le LCP image — le biggest CWV miss.
  3. 404 views returning 200 — utiliser le built-dans notFound() à retourner a réel status; soft 404s sont rampant on Suivant.js sites.
  4. metadata exported depuis a Client Component — silently ne fait pashing; c’est Serveur Component seulement.
  5. CSR pour principal contenu — fetching critical contenu dans useEffect signifie non-Google robots d’exploration obtenir vide pages.
  6. Hash (#) routing au lieu de le History API — ceux views ne sont pas séparément crawlable.
  7. Pas exporting generateStaticParams — dynamic routes rendre on-demand au lieu de étant pre-built.
  8. openGraph overwritten par layout inheritance — child segments remplacer, pas merge.
  9. Blocking JS/CSS dans robots.txt or via a Contenu Security Policy que arrête Googlebot’s headless Chrome depuis chargement scripts — tester avec Inspection d’URL.

Deployment notes

Suivant.js est construit par Vercel; hosting là donne tight integration (edge CDN pour static et ISR pages, bon TTFB) mais n’est pas requis. Define redirection permanentes dans redirects() dans next.config.js (renvoie 308, or 301 avec permanent: true) pour fiable signaling à robots d’exploration, définir security et mise en cache headers via headers(), et utiliser X-Robots-Tag réponse headers pour path-based noindex règles quand per-page robots metadata est awkward.

Ce que à vérifier où. Cache state, code d’états, redirections, et streamed metadata ne pas tout montrer up dans le même tester — a route peut regarder fine dans un vérifier et encore être broken dans un autre:

VérifierOù à regarderPourquoi il peut differ depuis ce que vous voir rendu
Cache/revalidation ageRéponse headers on a direct requête (curl -I)ISR peut servir a stale page on la requête correct après le window expires
Direct HTTP statuscurl -I on le production URL, pas le rendu UIA “pas trouvé” view sans notFound() encore renvoie 200
Redirection behaviorLe réel context que fires il — redirect() dans a Serveur Action, a Route Handler, vs. a client onClickCode d’état et réponse chemin differ par invocation context, pas simplement le destination
Streamed metadataDirect requête et client-side navigation à le même routeOrdinary clients peut obtenir streamed metadata; HTML-limited bots obtenir blocking metadata; le deux paths ne sont pas identical
Client-side transitionsNavigate dans-app, alors re-vérifier le <head>A route c’est correct on premier charger peut drift après a client transition

None de ce est guaranteed par le framework — Suivant.js donne vous le mechanisms (redirects(), notFound(), revalidation, streaming), mais cache keys, invalidation, preview state, et deployment configuration sont encore votre responsibility à obtenir correct et à tester dans production, pas simplement locally.

«One last note on dynamic rendering — serving prerendered HTML to bots and JavaScript to users. Google has deprecated it as a recommendation: “dynamic rendering was a workaround and not a long-term solution.” You don’t need it on Next.js anyway — SSR, SSG, ISR, and Server Components all put content in the HTML natively. Mention it so you recognize it in an audit; don’t build on it. » (Traduction) (Résumé en français de la section soixante-seize, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Le happy chemin: App Router + Serveur Components + ISR + le Metadata API (avec metadataBase) + next/image avec priority. Obtenir ceux correct et la plupart de Suivant.js SEO est handled.

Ajouter une note d’expert

Épingler une citation d’expert

Nouvelle personne ? Créez son profil non revendiqué à /admin/experts/ → Épingler une citation d’expert d’abord.