A sitemap lists every URL on your site that you want search engines to discover, along with metadata like how often it changes. This lesson covers generating one automatically with the sitemap.ts convention.
sitemap.ts: A Sitemap as Code
Creating a file named sitemap.ts directly inside app/ and exporting a default function that returns an array of URL entries is all it takes — Next.js automatically serves the result as a properly formatted sitemap.xml at /sitemap.xml, with no manual XML writing required.
Because it's a regular TypeScript function, it can fetch data — meaning a sitemap for a blog can include every published post's URL dynamically, staying in sync with your actual content without manual updates.
// app/sitemap.ts
import type { MetadataRoute } from "next";
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: "https://example.com",
lastModified: new Date(),
changeFrequency: "yearly",
priority: 1,
},
{
url: "https://example.com/about",
lastModified: new Date(),
changeFrequency: "monthly",
priority: 0.8,
},
];
}
Visiting /sitemap.xml now returns a properly formatted XML sitemap generated from this array.
url is the only required field; it must be the fully-qualified URL, including the domain.
changeFrequency is a hint to crawlers about how often content typically changes.
priority is a relative hint (0 to 1) about a page's importance compared to others in the sitemap.
Search engines treat these fields as suggestions, not guarantees, but they're still worth setting accurately.
Sitemap Cheat Sheet
Key facts about the sitemap.ts convention.
Question
Answer
File location
app/sitemap.ts
Resulting URL
/sitemap.xml
Can it be async?
Yes, for fetching dynamic content
Required field per entry
url
Multiple sitemaps for large sites
Supported via a generateSitemaps export
Building a Sitemap from Dynamic Content
For a blog or e-commerce site, combine static entries (home, about, contact) with dynamically generated entries for every post or product, fetched the same way you would in any Server Component.
Sitemaps have a practical size limit (traditionally 50,000 URLs per file). For very large sites, Next.js supports generating multiple sitemap files via a generateSitemaps export, which Next.js then indexes automatically.
Common Mistakes
Using relative URLs instead of fully-qualified URLs (including the domain) in sitemap entries.
Forgetting to update lastModified when content actually changes, reducing the sitemap's usefulness.
Including URLs that are blocked by robots.txt, which is contradictory to search engines.
Not paginating extremely large sitemaps, risking exceeding practical size limits.
Key Takeaways
app/sitemap.ts generates /sitemap.xml automatically from an exported function.
The function can be async, allowing dynamic entries built from real content.
Only url is required per entry; lastModified, changeFrequency, and priority are optional hints.
Very large sites can split sitemaps using a generateSitemaps export.
Keep sitemap entries and robots.txt rules consistent with each other.
Pro Tip
Regenerate lastModified values from your actual content's update timestamps (not just new Date() at build time) — an accurate lastModified gives search engines a genuinely useful signal about which pages have meaningfully changed since their last crawl.
You now know how to generate sitemaps. Next, learn how robots.txt controls what search engine crawlers are allowed to access.