Generating a Sitemap
A sitemap is an XML file that lists every URL on your site, helping search engines like Google and Bing discover, crawl, and index your pages efficiently. For content-heavy Astro sites with many static pages, a sitemap is one of the highest-leverage SEO additions you can make. Rather than maintain this file by hand, Astro provides the official @astrojs/sitemap integration, which generates an up-to-date sitemap at build time with zero runtime cost — perfectly in line with Astro’s zero-JS-by-default philosophy.
Installing the integration
The fastest way to add the integration is with the astro add command, which installs the package and wires it into your config automatically.
npx astro add sitemap
If you prefer to do it manually, install the package and register it yourself:
npm install @astrojs/sitemap
// astro.config.mjs
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://example.com",
integrations: [sitemap()],
});
The
siteoption is required. The integration uses it to construct absolute URLs for every entry. Withoutsite, no sitemap is generated and you will see a build warning.
How generation works
The sitemap is produced during astro build. The integration scans all final page routes — static pages, dynamic routes that have been pre-rendered via getStaticPaths, and content collection pages — and emits the results into your output directory.
npm run build
Output:
12:04:21 [@astrojs/sitemap] `sitemap-index.xml` created at `dist`
For larger sites the integration writes a sitemap-index.xml that references one or more chunked sitemap-0.xml files (each capped at 45,000 entries, just under the 50,000-URL limit of the sitemap spec). You then submit the index file to search engines.
Referencing the sitemap
Point crawlers at your sitemap by adding a <link> to your document head and a reference in robots.txt.
---
// src/layouts/BaseLayout.astro
const { title } = Astro.props;
---
<html lang="en">
<head>
<title>{title}</title>
<link rel="sitemap" type="application/xml" href="/sitemap-index.xml" />
</head>
<body>
<slot />
</body>
</html>
A matching robots.txt lives in your public/ directory so it is served at the site root:
User-agent: *
Allow: /
Sitemap: https://example.com/sitemap-index.xml
Configuration options
The integration accepts an options object to filter, customize, and enrich the generated entries.
| Option | Type | Description |
|---|---|---|
filter | (page: string) => boolean | Return false to exclude a URL from the sitemap. |
customPages | string[] | Extra absolute URLs to include (e.g. routes Astro can’t detect). |
changefreq | string | Default change frequency hint (daily, weekly, etc.). |
priority | number | Default priority between 0.0 and 1.0. |
lastmod | Date | Default last-modified timestamp for all entries. |
entryLimit | number | Max URLs per sitemap file before chunking (default 45000). |
serialize | (item) => SitemapItem | Transform or drop each entry programmatically. |
Here is a richer configuration that excludes admin pages, sets defaults, and tweaks a specific route:
// astro.config.mjs
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";
export default defineConfig({
site: "https://example.com",
integrations: [
sitemap({
filter: (page) => !page.includes("/admin/"),
changefreq: "weekly",
priority: 0.7,
lastmod: new Date(),
serialize(item) {
if (item.url === "https://example.com/") {
item.priority = 1.0;
item.changefreq = "daily";
}
return item;
},
}),
],
});
Note that
changefreqandpriorityare advisory hints. Modern search engines, including Google, largely ignore them — accuratelastmodvalues are far more valuable. Don’t over-invest in tuning priorities.
Internationalized sitemaps
If your site ships multiple locales, the i18n option emits xhtml:link alternate annotations so crawlers understand which pages are translations of one another.
sitemap({
i18n: {
defaultLocale: "en",
locales: {
en: "en-US",
fr: "fr-FR",
es: "es-ES",
},
},
});
This requires your URL structure to include the locale key as a path segment (for example /fr/about), matching the locales map above.
Best practices
- Always set a correct
siteinastro.config.mjs— it is mandatory and drives every absolute URL. - Submit
sitemap-index.xml, not an individual chunk file, to Google Search Console and Bing Webmaster Tools. - Use
filterto keep noindex, draft, utility, and authenticated routes out of the sitemap so crawl budget goes to real content. - Provide an accurate
lastmod(ideally derived from content collection dates) instead of obsessing overchangefreqandpriority. - Reference the sitemap from
robots.txtand a<link rel="sitemap">so crawlers can find it without manual submission. - Re-run
astro buildand re-deploy whenever you add or remove pages so the sitemap stays in sync with your live site.