Adios
BlogNext.js SEO

Next.js SEO

SEO con Next.js in produzione: guida completa

Configura la SEO di Next.js con rendering sul server, metadati, URL canonici, sitemap, JSON-LD, Core Web Vitals e verifiche del rilascio di produzione.

Team di AdiosAggiornato 17 luglio 202613 min di lettura

La SEO con Next.js in produzione è un contratto per route: ogni URL pubblico richiede una risposta utile, contenuti renderizzati sul server, metadati coerenti, una regola chiara di indicizzabilità e una verifica del rilascio che dimostri l'arrivo di quei segnali in produzione.

Assegna una funzione a ogni route indicizzabile

Next.js offre API di rendering e metadati; non decide quali pagine meritino traffico di ricerca. Parti definendo lettore, query, risposta, URL canonico e azione successiva per ogni route pubblica. Questa decisione distingue una pagina utile da un duplicato soltanto tecnicamente indicizzabile.

Associa un URL stabile a ogni intento distinto. Panoramica del prodotto, guida all'implementazione, pagina dei prezzi e riferimento API possono trattare lo stesso prodotto perché rispondono a esigenze diverse. Due pagine che ripetono la stessa risposta con titoli diversi offrono una scelta meno utile ai lettori e un'altra pagina da mantenere al team.

Registra la decisione in un inventario delle route prima di scrivere i metadati. Includi pattern della route, fonte dei dati, modalità di rendering, regola canonica, indicizzabilità ed evento di aggiornamento. L'inventario diventa il contratto condiviso per contenuti, ingegneria e verifiche del rilascio.

  • —Indicizza pagine che offrono una risposta completa e autonoma.
  • —Tieni fuori dall'indice pagine private, vuote, di ricerca interna, di anteprima e di filtri con poco valore.
  • —Usa l'URL canonico nei link interni, senza affidarti al tag canonico per correggere una navigazione incoerente.
  • —Collega gli aggiornamenti dei contenuti a eventi reali come modifiche di prodotto, revisioni editoriali o variazioni delle scorte.

Inserisci la risposta principale nella prima risposta HTML

Pagine e layout dell'App Router sono Server Components per impostazione predefinita. Usa questo comportamento per titolo, introduzione, testo principale, fatti del prodotto, breadcrumb e link contestuali. La risposta iniziale contiene così la risposta principale della pagina senza attendere una richiesta dal browser.

Un Client Component è adatto quando una funzionalità richiede stato, un gestore di eventi, un hook del ciclo di vita o un'API del browser. Mantieni quel confine vicino all'interazione. Un calcolatore dei prezzi può essere interattivo senza trasformare la pagina prodotto circostante in una struttura renderizzata nel client.

Il rendering decide anche come mantenere aggiornati i dati. La generazione statica è adatta a contenuti che cambiano con un rilascio. Il rendering sul server è adatto a dati pubblici specifici della richiesta. Quello in cache è adatto a dati condivisi con un evento di invalidazione definito. Scegli il modello più limitato che mantenga corretta la risposta visibile; non rendere dinamica un'intera route per supportare un piccolo controllo.

Crea una gerarchia dei metadati adatta alle route reali

Imposta metadataBase, un modello di titolo, la descrizione predefinita e i campi comuni di condivisione nel layout radice. Sostituisci i valori nel layout o nella pagina più specifica che li gestisce. Le route statiche possono esportare metadata; quelle basate sui dati possono usare generateMetadata. Entrambe le API funzionano solo sul server.

Tratta i metadati annidati come oggetti completi nella route che li sostituisce. Next.js unisce i metadati dalla radice alla pagina, ma sostituisce i campi annidati senza unione ricorsiva. Un oggetto openGraph della pagina può scartare accidentalmente un'immagine ereditata se fornisce soltanto un nuovo titolo.

Le versioni attuali di Next.js possono inviare metadati in streaming ai bot che eseguono JavaScript, mentre attendono i metadati per i bot limitati all'HTML. Questo migliora i tempi di risposta, ma non rende innocue query di metadati lente o inaffidabili. Riusa i dati risolti della pagina, gestisci esplicitamente entità mancanti e verifica sia route valide sia mancanti.

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 })),
    },
  };
}

Tratta URL canonici, reindirizzamenti e robots come un'unica politica degli URL

Un URL canonico identifica la versione preferita di contenuti duplicati o sostanzialmente simili. Rendi questa preferenza coerente tra reindirizzamenti, indicazioni canonical, link interni e voci delle sitemap. Google descrive reindirizzamenti e indicazioni rel=canonical come segnali forti e l'inclusione nella sitemap come segnale più debole; segnali allineati sono più facili da interpretare di un tag correttivo circondato da contraddizioni.

Definisci una sola volta protocollo approvato, hostname, regola sulla barra finale, politica di maiuscole e minuscole e comportamento dei parametri. Reindirizza varianti di host e percorso che non devono restare accessibili. Usa un URL canonico che punti alla pagina preferita stessa quando aiuta a mantenere coerenti gli URL generati.

Usa metadati robots per controllare se una pagina raggiungibile può essere indicizzata e robots.txt per orientare la scansione. Nessuno dei due protegge contenuti privati. L'autorizzazione deve rifiutare una richiesta non autenticata indipendentemente dalle intestazioni del crawler inviate. Non includere noindex nella prima risposta per tentare di rimuoverlo nel browser: Google può fermarsi prima di renderizzare la modifica 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 },
};

Genera i file dei crawler dai contenuti pubblicati

Genera sitemap.ts e robots.ts dalla stessa fonte che definisce i contenuti pubblici. La sitemap deve contenere URL assoluti e canonici che vuoi far scoprire ai motori di ricerca. Escludi route degli account, anteprime, risultati di ricerca interna, percorsi reindirizzati e combinazioni di parametri prive di valore autonomo.

Usa lastModified solo quando rappresenta un aggiornamento significativo a contenuto principale, dati strutturati o link della pagina. Google ignora priority e changefreq delle sitemap, quindi questi campi non correggono un elenco di URL obsoleto o pieno di rumore. Per cataloghi grandi, dividi le sitemap per famiglia di contenuti quando rende più chiare generazione, monitoraggio o responsabilità.

Usa robots.txt per orientare la scansione, non per nascondere contenuti. Un URL bloccato può comunque essere noto tramite link esterni e bloccare una pagina può impedire al crawler di vedere la regola noindex. Rimuovi le route sensibili dai percorsi pubblici di scoperta e applica il controllo di accesso nell'applicazione.

  • —Recupera la sitemap di produzione e conferma che restituisca XML con stato di successo.
  • —Seleziona URL da ogni famiglia di contenuti e verifica che ciascuno si risolva senza reindirizzamento.
  • —Confronta il numero di URL della sitemap con i record pubblicati e canonici nella fonte dei contenuti.
  • —Segnala URL generati con noindex, mancanti, reindirizzati o con URL canonico altrove.

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,
    }));
}

Descrivi le entità visibili con JSON-LD accurato

I dati strutturati identificano le entità già presentate dalla pagina. Scegli il tipo dalla sua finalità reale: Article per un post editoriale, Product per un articolo acquistabile, BreadcrumbList per la gerarchia o SoftwareApplication per un prodotto software reale. Aggiungere un tipo non cambia ciò che la pagina è.

Includi le proprietà obbligatorie del risultato di ricerca desiderato e mantieni i valori coerenti con i contenuti visibili. Non inventare recensioni, valutazioni, prezzi, disponibilità, autori o date di aggiornamento. Un markup completo e accurato è più utile di un grande oggetto composto da campi che la pagina non può giustificare.

Renderizza JSON-LD sul server e sanitizza il valore serializzato quando contiene dati che non controlli completamente. Valida l'URL distribuito con uno strumento per dati strutturati e poi esamina personalmente lo script. Il successo del parser conferma la sintassi; non dimostra che l'entità sia veritiera, aggiornata o idonea a un risultato avanzato.

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>;

Proteggi l'esperienza della pagina nella separazione tra componenti

Il lavoro SEO fallisce quando il risultato è tecnicamente indicizzabile ma frustrante da usare. Limita il confine del client, riserva spazio alle immagini, carica solo i file dei font usati dal design e mostra fallback utili per le sezioni secondarie lente. La prima schermata deve contenere la risposta principale, anziché una struttura vuota o un layout che si sposta all'arrivo delle risorse.

Misura route rappresentative in produzione, non soltanto una homepage curata. Largest Contentful Paint misura il caricamento, Interaction to Next Paint la reattività e Cumulative Layout Shift la stabilità visiva. Valuta il 75° percentile delle visite reali quando sono disponibili dati sul campo, poi usa test di laboratorio per riprodurre una regressione specifica.

Quando una route rallenta, indaga la causa prima di rimuovere contenuti utili. Cause comuni includono un perimetro Client Component ampliato, una query di dati bloccante, uno script di terze parti senza limiti, un'immagine principale troppo grande o una configurazione dei font che ritarda il testo. La correzione deve preservare la funzione della pagina.

  • —Misura almeno un articolo, una pagina di elenco e una pagina di dettaglio basata sui dati.
  • —Registra LCP, INP e CLS separatamente, senza ridurli a un unico punteggio.
  • —Confronta visite dirette e navigazione lato client tra le route.
  • —Ripeti i test dopo una distribuzione, perché CDN, ambiente di esecuzione e comportamento di terze parti influenzano il risultato in produzione.

Esegui una verifica SEO di Next.js in 15 minuti prima del rilascio

La configurazione SEO non è conclusa solo perché il codice sembra corretto. Compila l'applicazione di produzione, avvia lo stesso ambiente di esecuzione previsto per la distribuzione e verifica l'URL della candidata prima di assegnarle il dominio canonico. Una query di metadati può interrompere la compilazione, un reindirizzamento può eliminare una sezione e una route può restituire una pagina personalizzata di contenuto non trovato con lo stato sbagliato.

Verifica una pagina nota, un reindirizzamento, una pagina mancante e una route dinamica rappresentativa. Esamina la prima risposta HTML per titolo, descrizione, URL canonico, regola robots, H1, risposta iniziale, dati strutturati e link contestuali. Recupera robots.txt e sitemap.xml separatamente e confronta i loro URL con l'inventario delle route.

Registra le verifiche accanto al rilascio, senza affidarti alla memoria. Se una verifica critica per la SEO fallisce, mantieni attiva la versione sana corrente, correggi la candidata ed esegui di nuovo gli stessi controlli. Il risultato utile è una route di produzione la cui risposta rispetti la politica approvata, non un documento di controllo perfetto.

  • —Conferma che query principale e risultato atteso dal lettore corrispondano ancora alla pagina visibile.
  • —Conferma che risposta principale e link scansionabili siano presenti nella prima risposta HTML.
  • —Conferma che titolo, descrizione, URL canonico, regola robots e H1 descrivano la stessa pagina.
  • —Conferma che i dati strutturati corrispondano ai fatti visibili e vengano analizzati correttamente sull'URL distribuito.
  • —Conferma che gli URL delle sitemap siano canonici, indicizzabili, accessibili con stato di successo e accompagnati da date significative.
  • —Conferma che route rappresentative rispettino il budget di prestazioni in produzione del team.

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
Tutti gli articoli