P PasteCode
Guía de trabajo

Prompt-to-PR: Agregar un Sitemap y robots.txt

SOP para agregar un sitemap XML dinámico y robots.txt a un proyecto Next.js o Astro — lastmod, prioridad y reglas de rastreo correctas para SEO en producción.

CursorClaude CodeCodexWindsurf Next.jsAstroTypeScript
.md .json Dificultad: Fácil Actualizado 8 jun 2026

Los sitemaps y robots.txt son las primeras primitivas SEO que un agente toca, y a menudo son incorrectos — formato lastmod equivocado, directiva Sitemap: faltante en robots, o páginas bloqueadas incluidas inadvertidamente. Este manual los hace correctos.

1. Requisito

Producir un sitemap XML que cubra todas las rutas públicas (contenido estático + dinámico de la base de datos) y un robots.txt que bloquee rutas de administración/API y haga referencia al sitemap. Funciona tanto para Next.js App Router como para Astro; elige el enfoque correcto para tu framework.

2. Primer Prompt

First Prompt
Add a sitemap.xml and robots.txt to this project. Use the correct approach
for the framework detected below.
### If Next.js 14+:
1. Create `src/app/sitemap.ts` using the Next.js `MetadataRoute.Sitemap`
return type. Include:
- All static routes: /, /pricing, /blog, /about (hardcoded is fine).
- All dynamic blog posts: fetch slugs from the DB using the existing
query helper, return lastModified from the post's updatedAt field.
- Use `process.env.NEXT_PUBLIC_APP_URL` as the base URL.
- Correct W3C datetime format for lastModified (ISO 8601).
2. Create `src/app/robots.ts` using MetadataRoute.Robots.
- Allow: all routes.
- Disallow: /admin, /api, /dashboard.
- Add `sitemap: process.env.NEXT_PUBLIC_APP_URL + "/sitemap.xml"`.
### If Astro:
1. Add `@astrojs/sitemap` integration. In astro.config.ts, add
`sitemap({ filter: (page) => !page.includes("/admin") })` and set
`site: process.env.SITE_URL`.
2. Create `public/robots.txt`:
User-agent: *
Disallow: /admin
Disallow: /api
Sitemap: <SITE_URL>/sitemap-index.xml
Do not create a custom sitemap endpoint if the integration handles it.
Do not block / or any public content pages.

3. Cambios de Archivos Esperados

### Next.js
src/app/sitemap.ts (new — dynamic MetadataRoute.Sitemap)
src/app/robots.ts (new — MetadataRoute.Robots)
### Astro
astro.config.ts (add sitemap integration + filter)
public/robots.txt (new)
.env.example (SITE_URL added if missing)

4. Lista de Verificación

  • La URL base proviene de una variable de entorno — no codificada como http://localhost:3000.
  • lastModified es un objeto Date de JavaScript (Next.js lo convierte a ISO 8601) o ya una cadena ISO válida — no "undefined" o faltante.
  • /admin, /api, y /dashboard están en la lista Disallow.
  • La directiva Sitemap: en robots.txt usa una URL absoluta.
  • Las rutas dinámicas (publicaciones de blog) se incluyen mediante una consulta a la base de datos, no solo rutas estáticas.
  • El sitemap no incluye páginas 404, de redirección o noindex.
  • bun run build y luego curl /sitemap.xml devuelve XML válido (verificar con xmllint).

5. Comandos de Prueba

Terminal window
bun run build && bun run start
# or for Astro:
bun run build && bun run preview
# Validate sitemap XML
curl -s http://localhost:3000/sitemap.xml | xmllint --format - | head -40
# Confirm robots.txt
curl http://localhost:3000/robots.txt
# Confirm admin is disallowed and sitemap directive is present
grep -E "Disallow|Sitemap" <(curl -s http://localhost:3000/robots.txt)
# Google Rich Results / URL Inspection simulation
curl -A "Googlebot" http://localhost:3000/sitemap.xml -I

6. Fallos Comunes

  • lastModified es "undefined" — el campo updatedAt de la publicación es nulo. Protección: lastModified: post.updatedAt ?? post.createdAt ?? new Date().
  • El sitemap devuelve 404src/app/sitemap.ts falta o está fuera del directorio app.
  • Todas las rutas deshabilitadas — el agente agrega Disallow: / por error. Confirma que solo las rutas de administración/API están bloqueadas.
  • La directiva Sitemap: tiene URL relativa — Google la ignora. Debe ser absoluta: https://example.com/sitemap.xml.
  • Solo sitemap estático — el agente codifica slugs de blog en lugar de consultar la base de datos. Confirma que la función del sitemap es async y obtiene datos reales.

7. Prompt de Corrección

Fix Prompt
The sitemap.xml at /sitemap.xml includes every blog post with
lastModified "undefined" (rendered as the string).
Fix in src/app/sitemap.ts:
const posts = await getBlogPosts();
return posts.map((post) => ({
url: `${BASE_URL}/blog/${post.slug}`,
lastModified: post.updatedAt ?? post.createdAt ?? new Date(),
changeFrequency: "weekly",
priority: 0.8,
}));
Ensure getBlogPosts() returns rows that include updatedAt and createdAt.

8. Descripción de PR

PR description
## SEO: Add dynamic sitemap.xml and robots.txt
**Next.js**: `src/app/sitemap.ts` + `src/app/robots.ts` using built-in
`MetadataRoute` types. Sitemap includes static routes + all published blog
posts with correct `lastModified` timestamps from the DB.
**robots.txt** disallows `/admin`, `/api`, `/dashboard`; includes absolute
`Sitemap:` directive pointing to the generated `/sitemap.xml`.
Base URL read from `NEXT_PUBLIC_APP_URL` — no localhost URLs in production.