Blog Build a sitemap and robots file in Next.js
Build a sitemap and robots file in Next.js
TL;DR Add sitemap.ts and robots.ts in the app directory. Each default-exports a function returning a typed object, and Next serves them at /sitemap.xml and /robots.txt. Generate the entries from your real content so they never drift out of sync.
Next.js gives you sitemaps and a robots file as first-class conventions, so you do not need a plugin or a hand-maintained XML file. Two small files in the app directory keep both in sync with your real routes. Here is how.
The sitemap
Create app/sitemap.ts that default-exports a function returning your URLs.
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
const base = "https://example.com";
return [
{ url: `${base}/`, lastModified: new Date("2026-01-01"), priority: 1 },
{ url: `${base}/about`, lastModified: new Date("2026-01-01") },
];
}
Next serves this at /sitemap.xml and handles the XML for you.
Include dynamic pages
The real power is generating entries from your content. Read your posts and map them:
const posts = getAllPosts().map((p) => ({
url: `${base}/blog/${p.slug}`,
lastModified: new Date(p.updated),
}));
Because the file runs at build time, the sitemap regenerates from your actual posts on every build. Add a post, rebuild, and it appears with no manual step.
The robots file
Create app/robots.ts alongside it.
import type { MetadataRoute } from "next";
export default function robots(): MetadataRoute.Robots {
return {
rules: [{ userAgent: "*", allow: "/", disallow: ["/admin/"] }],
sitemap: "https://example.com/sitemap.xml",
};
}
Point it at your sitemap so crawlers discover it, and never block the paths that hold your CSS and JS, because crawlers need them to render the page.
Two details worth getting right
- Real lastmod dates. Use each page's actual last-modified date, not the build time. A lastmod that changes every deploy tells search engines nothing and may be ignored.
- Only canonical, indexable URLs. Leave out redirects, error pages, and anything you mark noindex, so the sitemap is a clean list of pages you want found.
That is the whole setup: two files, generated from your content, always in step with the site. For more on the markup side, see how to add JSON-LD.
FAQ
Do I need a plugin for a Next.js sitemap?
No. The App Router has built-in conventions: a sitemap.ts file exporting a function that returns your URLs, and a robots.ts file for the rules. Next serves them at the right paths and handles the XML formatting.
How do I include dynamic pages like blog posts?
Read your content inside sitemap.ts and map it to entries. Because the file runs at build time, the sitemap regenerates from your actual posts on every build, so new pages appear without manual edits.
Should lastmod be the build time?
No. Use the real last-modified date of each page, for example a post's updated field. A lastmod that changes on every deploy is unreliable and search engines may ignore it.