Next.js SEO
SEO de Next.js para producción: guía completa
Configura el SEO de Next.js con renderizado en el servidor, metadatos, URL canónicas, sitemaps, JSON-LD, Core Web Vitals y comprobaciones de las versiones de producción.
El SEO de Next.js en producción es un contrato por ruta: cada URL pública necesita una respuesta útil, contenido renderizado en el servidor, metadatos coherentes, una regla clara de indexabilidad y una comprobación de la versión que demuestre que esas señales llegaron a producción.
Asigna una función a cada ruta indexable
Next.js proporciona API de renderizado y metadatos; no decide qué páginas merecen tráfico de búsqueda. Empieza por definir el lector, la consulta, la respuesta, la URL canónica y la siguiente acción de cada ruta pública. Esa decisión distingue una página útil de un duplicado técnicamente indexable.
Asigna una URL estable a cada intención distinta. Una presentación del producto, una guía de implementación, una página de precios y una referencia de API pueden hablar del mismo producto porque responden a necesidades diferentes. Dos páginas que repiten la misma respuesta con encabezados distintos ofrecen una opción menos útil a los lectores y añaden otra página que el equipo debe mantener.
Registra la decisión en un inventario de rutas antes de escribir los metadatos. Incluye el patrón de ruta, la fuente de datos, el modo de renderizado, la regla canónica, la indexabilidad y el evento que activa la actualización. El inventario se convierte en el contrato compartido para el contenido, la ingeniería y las comprobaciones de las versiones.
- —Indexa las páginas que ofrecen una respuesta completa e independiente.
- —Mantén fuera del índice las páginas privadas, vacías, de búsqueda interna, de vista previa y de filtros con poco valor.
- —Usa enlaces internos a la URL canónica, en lugar de depender de una etiqueta canónica para corregir una navegación inconsistente.
- —Asocia las actualizaciones de contenido a eventos reales, como un cambio de producto, una revisión editorial o una actualización de inventario.
Incluye la información principal en la primera respuesta HTML
Las páginas y los layouts de App Router son Server Components por defecto. Usa ese comportamiento para el título, la introducción, el cuerpo del texto, los datos del producto, las rutas de navegación y los enlaces contextuales. Así, la respuesta inicial contiene la información principal de la página sin esperar a una solicitud desde el navegador.
Un Client Component es adecuado cuando la función necesita estado, un manejador de eventos, un hook del ciclo de vida o una API del navegador. Mantén ese límite cerca de la interacción. Una calculadora de precios puede ser interactiva sin convertir toda la página de producto que la rodea en una estructura renderizada en el cliente.
El renderizado también implica decidir cómo mantener actualizado el contenido. La generación estática encaja con el contenido que cambia con una versión. El renderizado en el servidor encaja con los datos públicos específicos de cada solicitud. El renderizado con caché encaja con los datos compartidos que tienen un evento de invalidación definido. Elige el modelo más limitado que mantenga correcta la información visible; no conviertas toda una ruta en dinámica para admitir un pequeño control.
Crea una jerarquía de metadatos que funcione con rutas reales
Configura metadataBase, una plantilla de título, la descripción predeterminada y los campos compartidos para redes sociales en el layout raíz. Sustituye los valores en el layout o la página de ámbito más específico al que pertenezcan. Las rutas estáticas pueden exportar metadata; las rutas basadas en datos pueden usar generateMetadata. Ambas API son exclusivas del servidor.
Trata los metadatos anidados como objetos completos en la ruta que los sustituya. Next.js combina los metadatos desde la raíz hacia la página, pero reemplaza los campos anidados en lugar de combinarlos en profundidad. Un objeto openGraph de una página puede descartar accidentalmente una imagen heredada si solo aporta un título nuevo.
Las versiones actuales de Next.js pueden transmitir metadatos mediante streaming para los bots que ejecutan JavaScript, mientras mantienen una respuesta bloqueante de metadatos para los bots limitados a HTML. Ese comportamiento mejora los tiempos de respuesta, pero no elimina las consecuencias de las consultas de metadatos lentas o poco fiables. Reutiliza los datos resueltos de la página, gestiona explícitamente las entidades inexistentes y prueba tanto las rutas correctas como las inexistentes.
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 })),
},
};
}Trata las URL canónicas, las redirecciones y robots como una única política de URL
Una URL canónica identifica la versión preferida de un contenido duplicado o sustancialmente similar. Mantén esa preferencia coherente entre las redirecciones, las anotaciones canónicas, los enlaces internos y las entradas del sitemap. Google describe las redirecciones y las anotaciones rel=canonical como señales fuertes, y la inclusión en el sitemap como una señal más débil. Las señales alineadas son más fáciles de interpretar que una etiqueta correctiva rodeada de contradicciones.
Define una sola vez el protocolo aprobado, el nombre de host, la regla de barras finales, la política de mayúsculas y minúsculas y el comportamiento de los parámetros. Redirige las variantes de host y ruta que no deberían seguir siendo accesibles. Usa una URL canónica que apunte a la propia página preferida cuando ayude a mantener coherentes las URL generadas.
Usa los metadatos robots para controlar si una página accesible puede indexarse y robots.txt para orientar el rastreo. Ninguno protege el contenido privado. La autorización debe rechazar una solicitud no autenticada, independientemente de las cabeceras de rastreador que envíe. No incluyas noindex en la primera respuesta para intentar retirarlo después en el navegador: Google puede detenerse antes de renderizar el cambio de 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 los archivos para rastreadores a partir del contenido publicado
Genera sitemap.ts y robots.ts a partir de la misma fuente que define el contenido público. Un sitemap debe contener las URL absolutas y canónicas que quieres que descubran los buscadores. Excluye las rutas de cuentas, las vistas previas, los resultados de búsqueda interna, las rutas redirigidas y las combinaciones de parámetros que no aporten valor por sí solas.
Usa lastModified solo cuando represente una actualización significativa del contenido principal de la página, sus datos estructurados o sus enlaces. Google ignora los valores priority y changefreq del sitemap, así que esos campos no corrigen una lista de URL desactualizada o con ruido. Para un catálogo grande, divide los sitemaps por familia de contenido cuando eso aclare la generación, la supervisión o la responsabilidad.
Trata robots.txt como una guía de rastreo, en lugar de un mecanismo para ocultar contenido. Una URL cuyo rastreo esté bloqueado puede seguir siendo conocida por enlaces externos, y bloquear una página puede impedir que un rastreador vea su regla noindex. Excluye las rutas sensibles del descubrimiento público y exige el control de acceso en el límite de la aplicación.
- —Obtén el sitemap de producción y confirma que devuelve XML con un estado de éxito.
- —Selecciona una muestra de URL de cada familia de contenido y verifica que todas se resuelvan sin redirecciones.
- —Compara el número de URL del sitemap con los registros publicados y canónicos de la fuente de contenido.
- —Informa de las URL generadas que tengan noindex, no existan, estén redirigidas o indiquen otra URL canónica.
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,
}));
}Describe las entidades visibles con JSON-LD preciso
Los datos estructurados identifican las entidades que la página ya presenta. Elige el tipo según la finalidad real de la página: Article para una publicación editorial, Product para un artículo que se puede comprar, BreadcrumbList para la jerarquía o SoftwareApplication para un producto de software real. Añadir un tipo no cambia lo que es la página.
Incluye las propiedades que exige la función de búsqueda a la que te diriges y mantén los valores alineados con el contenido visible. No inventes reseñas, valoraciones, precios, disponibilidad, autores ni fechas de actualización. Un marcado completo y preciso es más útil que un objeto grande compuesto por campos que la página no puede respaldar.
Renderiza el JSON-LD en el servidor y sanea el valor serializado cuando contenga datos que no controles por completo. Valida la URL desplegada con una herramienta de datos estructurados y luego inspecciona tú mismo el script. Que el analizador lo acepte confirma la sintaxis, pero no demuestra que la entidad sea veraz, esté actualizada o cumpla los requisitos para un resultado enriquecido.
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>;Protege la experiencia de la página en el límite del componente
El trabajo de SEO falla cuando el resultado es técnicamente indexable pero resulta frustrante de usar. Mantén limitado el ámbito del cliente, reserva espacio para las imágenes, carga solo los archivos de fuentes que usa el diseño y muestra alternativas útiles mientras se cargan las secciones secundarias lentas. La primera pantalla debe contener la información principal, en lugar de una estructura vacía o un diseño que se desplaza al llegar los recursos.
Mide rutas representativas de producción, en lugar de una única página de inicio cuidadosamente optimizada. Largest Contentful Paint mide la carga; Interaction to Next Paint, la capacidad de respuesta; y Cumulative Layout Shift, la estabilidad visual. Evalúa el percentil 75 de las visitas reales cuando haya datos de campo y usa después pruebas de laboratorio para reproducir una regresión concreta.
Cuando una ruta se vuelva más lenta, inspecciona la causa antes de eliminar contenido útil. Las causas habituales incluyen ampliar el ámbito de un Client Component, una consulta de datos bloqueante, un script de terceros sin límites, una imagen principal demasiado grande o una configuración de fuentes que retrase el texto. La solución debe conservar la función de la página.
- —Mide al menos un artículo, una página de listado y una página de detalle basada en datos.
- —Registra LCP, INP y CLS por separado, en lugar de reducirlos a una única puntuación.
- —Compara las visitas directas con la navegación entre rutas del lado del cliente.
- —Repite las pruebas después de un despliegue, porque la CDN, el entorno de ejecución y el comportamiento de terceros afectan al resultado en producción.
Haz una comprobación de SEO de Next.js de 15 minutos antes de publicar la versión
La configuración de SEO no termina cuando el código parece correcto. Compila la aplicación de producción, inicia el mismo entorno de ejecución que planeas desplegar y verifica la URL de la versión candidata antes de asignarle el dominio canónico. Una consulta de metadatos puede hacer fallar una compilación, una redirección puede eliminar una sección y una ruta puede devolver una página de contenido no encontrado con un diseño completo pero un estado incorrecto.
Prueba una página existente, una redirección, una página inexistente y una ruta dinámica representativa. Inspecciona la primera respuesta HTML para comprobar el título, la descripción, la URL canónica, la regla robots, el H1, la respuesta inicial, los datos estructurados y los enlaces contextuales. Obtén robots.txt y sitemap.xml por separado y compara sus URL con el inventario de rutas.
Registra las comprobaciones junto a la versión, en lugar de confiar en la memoria. Si falla una comprobación crítica para el SEO, mantén activa la versión actual que funciona correctamente, corrige la versión candidata y repite las mismas comprobaciones. El resultado útil es una ruta de producción cuya respuesta coincida con la política aprobada, más allá de tener un documento de verificación perfecto.
- —Confirma que la consulta principal y el resultado que busca el lector sigan correspondiendo a la página visible.
- —Confirma que la información principal y los enlaces rastreables existan en la primera respuesta HTML.
- —Confirma que un título, una descripción, una URL canónica, una regla robots y un H1 describan la misma página.
- —Confirma que los datos estructurados coincidan con los hechos visibles y se puedan analizar en la URL desplegada.
- —Confirma que las URL del sitemap sean canónicas, indexables, devuelvan un estado de éxito y tengan fechas significativas.
- —Confirma que las rutas representativas cumplan el presupuesto de rendimiento de producción del equipo.
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