Con App Router elegimos entre app/robots.txt estático y app/robots.ts/app/robots.js generado. Usamos la opción menos dinámica que cubra el requisito.
Archivo estático
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap.xml
Es fácil de revisar y tiene pocas dependencias.
Ruta generada
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return { rules: { userAgent: '*', allow: '/' }, sitemap: 'https://example.com/sitemap.xml' }
}
Revisamos cache y comportamiento dynamic
Una ruta generada puede estar cacheada según su implementación. Confirmamos la documentación actual y la respuesta desplegada antes de asumir que un cambio de código ya está público.
Protegemos previews fuera de robots.txt
Staging privado necesita autenticación. También comprobamos que variables de entorno no generen un Sitemap: con dominio de preview.
Verificamos el deploy
Abrimos /robots.txt, usamos el validator y probamos URLs con el tester. Si el resultado difiere, revisamos routing, cache, environment variables y ownership del despliegue.
Comportamiento actual del App Router
Next.js admite un archivo estático app/robots.txt y una ruta generada app/robots.ts o app/robots.js que devuelve MetadataRoute.Robots. Las rutas metadata generadas pueden quedar cacheadas según su implementación, por lo que verificamos la versión del framework y la respuesta publicada en lugar de asumir que cada cambio se recalcula en cada request.
Elegimos estático cuando la política es estable. Generamos solo cuando aporta valor real, por ejemplo varios grupos de crawler o un hostname controlado por entorno. Evitamos dependencias remotas: robots.txt no debería fallar porque una API de configuración sea lenta.
Fallos que probamos en cada deploy
Buscamos sitemap con dominio de preview, middleware/proxy interceptando /robots.txt, coexistencia accidental de archivo estático y ruta generada, salida cacheada y ramas de staging seleccionadas en producción. El smoke test comprueba status, content-type, cuerpo y hostname del sitemap sobre el dominio público, no solo el objeto TypeScript.