Skip to content
Astro as seo 4 min read

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 site option is required. The integration uses it to construct absolute URLs for every entry. Without site, 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.

OptionTypeDescription
filter(page: string) => booleanReturn false to exclude a URL from the sitemap.
customPagesstring[]Extra absolute URLs to include (e.g. routes Astro can’t detect).
changefreqstringDefault change frequency hint (daily, weekly, etc.).
prioritynumberDefault priority between 0.0 and 1.0.
lastmodDateDefault last-modified timestamp for all entries.
entryLimitnumberMax URLs per sitemap file before chunking (default 45000).
serialize(item) => SitemapItemTransform 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 changefreq and priority are advisory hints. Modern search engines, including Google, largely ignore them — accurate lastmod values 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 site in astro.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 filter to 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 over changefreq and priority.
  • Reference the sitemap from robots.txt and a <link rel="sitemap"> so crawlers can find it without manual submission.
  • Re-run astro build and re-deploy whenever you add or remove pages so the sitemap stays in sync with your live site.
Last updated June 14, 2026
Was this helpful?