Ship app/sitemap.ts and app/robots.ts
Next.js App Router turns app/sitemap.ts and app/robots.ts into /sitemap.xml and /robots.txt at build time. Return only canonical, indexable URLs from sitemap.ts with honest lastModified values, and set the rules plus the sitemap location from robots.ts. Both files must be reachable without authentication and must not be shadowed by static files in public/.
Why this matters
Two file conventions give crawlers the map and the rules.
Before you start
- Next.js App Router project with a published-content data source
- A single production site URL constant
How to apply it
Create app/sitemap.ts
Export a default function returning MetadataRoute.Sitemap. Map published records to { url, lastModified }, using absolute URLs from siteUrl and the record updated timestamp rather than the build time.
Check: curl -s your production domain/sitemap.xml returns 200, is valid XML, and lists only canonical published URLs.
Split large catalogs with generateSitemaps
When the set exceeds 50,000 URLs or 50 MB, export generateSitemaps() returning ids and emit one file per id. Next.js then serves /sitemap/<id>.xml and an index at /sitemap.xml.
Check: curl -s your production domain/sitemap.xml returns a sitemap index and every child loc returns 200.
Add app/robots.ts
Return rules with userAgent '*', allow '/' and disallow only paths with no search value. Set sitemap to siteUrl + '/sitemap.xml' and host to the production origin so one file documents the whole crawl policy.
Check: curl -s your production domain/robots.txt returns 200, contains a Sitemap line and disallows no indexable path.
Remove shadowing static files
Delete public/robots.txt and public/sitemap.xml plus any proxy or edge rewrite for those paths. A static file or rewrite can serve instead of the metadata route and silently drop your changes.
Check: curl -sI your production domain/robots.txt returns 200 with text/plain, and the repo has no public/robots.txt.
Submit and monitor
Submit the sitemap in Search Console and compare discovered URLs with indexed ones. Confirm robots.txt does not block CSS, JavaScript or any path that must rank.
Check: The Search Console Sitemaps report lists the file as Success with a discovered URL count above zero.
Source: seo-mcp playbook · curated entry · report an error
Official references
Framework notes
nextjs-app
`app/sitemap.ts` and `app/robots.ts` export MetadataRoute objects; use `generateSitemaps()` above 50,000 URLs and delete `public/robots.txt`.
nextjs-pages
The Pages Router has no metadata routes; generate `/sitemap.xml` at build with `next-sitemap` (`next-sitemap` in a postbuild script) and keep `public/robots.txt` aligned.