Checklist de SEO para Next.js con el App Router, con código | We.Inc
Checklist de SEO para el App Router: metadata y generateMetadata, metadataBase, plantillas de título, canonical, hreflang, sitemap.ts, robots.ts e imágenes OG, con código.
Checklist de SEO para Next.js (App Router)
En el App Router, las etiquetas SEO salen de un objeto metadata exportado o de una función generateMetadata en los archivos layout y page, que solo funcionan en Server Components. Define metadataBase una vez en el layout raíz, añade app/sitemap.ts y app/robots.ts, da a cada ruta un canonical mediante alternates y coloca un archivo opengraph-image junto a las páginas que lo necesiten.
Dónde va cada pieza
Necesidad
Archivo o campo del App Router
Título y descripción
export const metadata o generateMetadata en page.tsx o layout.tsx
URL base para los enlaces relativos
metadataBase en app/layout.tsx
Canonical y hreflang
alternates.canonical y alternates.languages
app/sitemap.ts que devuelve MetadataRoute.Sitemap
app/robots.ts que devuelve MetadataRoute.Robots
Imagen para compartir
opengraph-image.png, .jpg, .gif o .tsx en la carpeta de la ruta
El App Router trae soluciones integradas para casi todas las tareas de SEO técnico, pero están repartidas en una docena de páginas de documentación. Esta checklist las reúne en orden, con código para copiar en cada punto, y las casillas te permiten seguir el avance de tu propio proyecto.
Recorre la checklist y marca cada punto cuando esté hecho. Las marcas solo se guardan en esta pestaña.
Copia primero el código del layout raíz, ya que metadataBase y la plantilla de título afectan a todas las demás rutas.
Añade los archivos de sitemap y robots, y luego visita /sitemap.xml y /robots.txt en tu servidor de desarrollo para leer el resultado.
Mira el código fuente de algunas rutas para confirmar que el título, el canonical y las etiquetas og están en el HTML.
Los objetos metadata se combinan de forma superficial. Si una página define openGraph, sustituye todo el objeto openGraph del layout, así que reparte los campos compartidos desde un archivo común.
Un title.template en un layout se aplica a los segmentos hijos, no a la página del propio layout, y necesita un title.default a su lado.
Usar una URL relativa en un campo de metadata sin metadataBase provoca un error de build, lo que sirve como aviso temprano.
Mantén page.tsx como Server Component para poder exportar metadata, y mueve los hooks y los manejadores de eventos a un archivo de componente de cliente aparte.
Preguntas frecuentes
¿Puedo usar generateMetadata en un componente de cliente?
No. El objeto metadata y generateMetadata solo se admiten en Server Components, porque Next.js tiene que resolverlos en el servidor antes de renderizar. Mantén la página como Server Component e importa un componente de cliente para las partes interactivas.
¿Por qué params es una Promise en generateMetadata?
Las versiones actuales de Next.js pasan params y searchParams como Promises, así que escribes const { slug } = await params dentro de un generateMetadata async. El código escrito para versiones anteriores que lee params.slug directamente necesita actualizarse.
¿Cómo hago un sitemap con más de 50,000 URL en Next.js?
Usa generateSitemaps en un archivo sitemap.ts. Devuelve una lista de ids, y el export por defecto genera un sitemap por id. En Next.js 16 el id llega como Promise. Los archivos se sirven en rutas como /product/sitemap/1.xml.
¿Next.js añade una etiqueta canonical automáticamente?
No, salvo que la definas tú. Añade alternates.canonical en la metadata de cada ruta, normalmente como ruta relativa, por ejemplo /blog/my-post, y deja que metadataBase la convierta en una URL completa.
¿Puedo exportar a la vez metadata y generateMetadata?
No, un segmento de ruta puede exportar uno u otro. Usa el objeto estático cuando nada dependa de la petición o de datos obtenidos, y generateMetadata cuando sí dependa.
Primero estático, dinámico donde haga falta
La mayoría de las páginas de marketing pueden usar el objeto metadata estático. Recurre a generateMetadata en rutas dinámicas como /blog/[slug] o /products/[id], donde el título sale de los datos.
Las llamadas fetch dentro de generateMetadata se memorizan junto con la misma petición de la página, así que cargar el post para la metadata y otra vez para renderizar no duplica el trabajo.
El renderizado sigue importando
Los Server Components envían HTML real, que es lo primero que leen los rastreadores y las vistas previas de enlaces. El contenido que solo aparece tras un fetch en el cliente tarda más en descubrirse y es invisible para las apps que no ejecutan JavaScript.
Desde la versión 15.2, la metadata de generateMetadata puede enviarse en streaming después del primer HTML para los navegadores. Para los bots que no pueden ejecutar JavaScript, como facebookexternalhit, Next.js sigue poniendo las etiquetas en el head, detectándolos por user agent.
Código para cada punto
Layout raíz: metadataBase, plantilla de título y valores por defecto
Se define una vez en app/layout.tsx. Las páginas hijas que exportan title: "Pricing" se muestran como Pricing | Northside.
Ruta dinámica: generateMetadata con canonical
params se espera con await. getPost representa tu propia función de datos.
app/sitemap.ts
Devuelve una entrada por URL. changeFrequency y priority son opcionales y Google los ignora, así que se omiten.
app/robots.ts
Genera robots.txt en la raíz del sitio.
app/blog/[slug]/opengraph-image.tsx
Dibuja una imagen para compartir de 1200 por 630 a partir del título del post con ImageResponse de next/og. Los exports alt, size y contentType se convierten en etiquetas og.
Límites de los archivos de imagen
Imágenes para compartir basadas en archivos
Archivo
Tipos
Límite de tamaño
.jpg, .jpeg, .png, .gif o .js, .ts, .tsx
8 MB (el build falla si lo supera)
.jpg, .jpeg, .png, .gif o .js, .ts, .tsx
5 MB (el build falla si lo supera)
.txt
Se convierte en og:image:alt
metadataBase definido en app/layout.tsx
Permite que todos los demás campos de URL sean rutas relativas
Plantilla de título más valor por defecto en el layout raíz
Da a cada página un sufijo coherente, como | Acme
Título y descripción únicos en cada página
Metadata estática o generateMetadata por ruta
Canonical en cada ruta indexable
hreflang para las rutas traducidas
alternates.languages, o en el sitemap
app/sitemap.ts solo incluye URL canónicas activas
Divídelo con generateSitemaps cuando sea grande
app/robots.ts con una línea de sitemap
Bloquea solo zonas como /admin o /api
Imagen Open Graph para las rutas clave
Archivo opengraph-image con texto alternativo
noindex en rutas pobres en contenido o privadas
robots: { index: false } en la metadata de esa ruta
Contenido renderizado en el servidor
Revisa el código fuente de la página, no solo lo que muestra el navegador