Sitemap & robots.txt
sitemap.xml lists the URLs worth indexing, and robots.txt tells crawlers which parts of the site they may (or may not) visit. Next.js lets you generate both dynamically with plain TypeScript files instead of hand-maintaining static XML and text files.Why both matter for SEO
File | What it does | Why it matters |
|---|---|---|
| Lists every URL you want indexed, often with last-modified dates and priority hints | Helps search engines discover pages faster, especially ones with few internal links pointing at them |
| Allows or disallows crawler access to specific paths, and can point to the sitemap | Keeps crawlers away from admin routes, search-result pages, or duplicate content, and saves crawl budget for pages that matter |
robots.ts
app/robots.ts file that exports a default function returning a MetadataRoute.Robots object. Next.js serves it at /robots.txt automatically.app/robots.ts
import type { MetadataRoute } from 'next'
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{
userAgent: '*',
allow: '/',
disallow: ['/admin', '/api'],
},
],
sitemap: 'https://example.com/sitemap.xml',
}
}sitemap.ts
A static site can hardcode an array of URLs. A content-driven site should generate the sitemap dynamically from whatever database or CMS holds the actual pages, so new content is picked up automatically without a manual sitemap update.
app/sitemap.ts — dynamic, database-driven
import type { MetadataRoute } from 'next'
import { getAllPosts } from '@/libs/posts'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts()
const postEntries = posts.map((post) => ({
url: `https://example.com/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly' as const,
priority: 0.7,
}))
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 1,
},
{
url: 'https://example.com/blog',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
},
...postEntries,
]
}/sitemap.xml, converting the returned array into valid sitemap XML for you — you never write XML by hand.generateSitemaps function alongside sitemap.ts, splitting the URL set across several numbered sitemap files that get linked from a sitemap index.app/robots.tsexports a default function returning crawl rules, served automatically at/robots.txt.app/sitemap.tsexports a default (async) function returning an array of URL entries, served at/sitemap.xml.A dynamic sitemap that pulls from your database/CMS keeps itself up to date as content changes, unlike a hand-maintained static file.
Point
robots.ts'ssitemapfield at your sitemap URL so crawlers discover it directly.Very large sites can split into multiple sitemap files via
generateSitemaps.