# @astrojs/sitemap

> Learn how to use the @astrojs/sitemap integration in your Astro project.

This **[Astro integration](/en/guides/integrations-guide/)** generates a sitemap based on your pages when you build your Astro project.

## Why Astro Sitemap

[Section titled “Why Astro Sitemap”](#why-astro-sitemap)

A Sitemap is an XML file that outlines all of the pages, videos, and files on your site. Search engines like Google read this file to crawl your site more efficiently. [See Google’s own advice on sitemaps](https://developers.google.com/search/docs/advanced/sitemaps/overview) to learn more.

A sitemap file is recommended for large multi-page sites. If you don’t use a sitemap, most search engines will still be able to list your site’s pages, but a sitemap is a great way to ensure that your site is as search engine friendly as possible.

With Astro Sitemap, you don’t have to worry about creating this XML file yourself: the Astro Sitemap integration will crawl your statically-generated routes and create the sitemap file, including [dynamic routes](/en/guides/routing/#dynamic-routes) like `[...slug]` or `src/pages/[lang]/[version]/info.astro` generated by `getStaticPaths()`.

This integration cannot generate sitemap entries for dynamic routes in [SSR mode](/en/guides/on-demand-rendering/).

## Installation

[Section titled “Installation”](#installation)

Astro includes an `astro add` command to automate the setup of official integrations. If you prefer, you can [install integrations manually](#manual-install) instead.

Run one of the following commands in a new terminal window.

* npm

  ```sh
  npx astro add sitemap
  ```

* pnpm

  ```sh
  pnpm astro add sitemap
  ```

* Yarn

  ```sh
  yarn astro add sitemap
  ```

If you run into any issues, [feel free to report them to us on GitHub](https://github.com/withastro/astro/issues) and try the manual installation steps below.

### Manual Install

[Section titled “Manual Install”](#manual-install)

First, install the `@astrojs/sitemap` package using your package manager.

* npm

  ```sh
  npm install @astrojs/sitemap
  ```

* pnpm

  ```sh
  pnpm add @astrojs/sitemap
  ```

* Yarn

  ```sh
  yarn add @astrojs/sitemap
  ```

Then, apply the integration to your `astro.config.*` file using the `integrations` property:

```diff
import { defineConfig } from 'astro/config';
+import sitemap from '@astrojs/sitemap';


export default defineConfig({
  // ...
  integrations: [sitemap()],
});
```

## Usage

[Section titled “Usage”](#usage)

`@astrojs/sitemap` needs to know your site’s deployed URL to generate a sitemap.

Add your site’s URL as the [`site`](/en/reference/configuration-reference/#site) option in `astro.config.mjs`. This must begin with `http://` or `https://`.

astro.config.mjs

```js
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [sitemap()],
  // ...
});
```

With the sitemap integration configured, `sitemap-index.xml` and `sitemap-0.xml` files will be added to your output directory when building your site.

`sitemap-index.xml` links to all the numbered sitemap files. `sitemap-0.xml` lists the pages on your site. For extremely large sites, there may also be additional numbered files like `sitemap-1.xml` and `sitemap-2.xml`.

Example of generated files for a two-page website

sitemap-index.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
  <sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://example.com/sitemap-0.xml</loc>
  </sitemap>
</sitemapindex>
```

sitemap-0.xml

```xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:news="http://www.google.com/schemas/sitemap-news/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1">
  <url>
    <loc>https://example.com/</loc>
  </url>
  <url>
    <loc>https://example.com/second-page/</loc>
  </url>
</urlset>
```

### Sitemap discovery

[Section titled “Sitemap discovery”](#sitemap-discovery)

You can make it easier for crawlers to find your sitemap with links in your site’s `<head>` and `robots.txt` file.

#### Sitemap link in `<head>`

[Section titled “Sitemap link in \<head>”](#sitemap-link-in-head)

Add a `<link rel="sitemap">` element to your site’s `<head>` pointing to the sitemap index file:

src/layouts/Layout.astro

```diff
<head>
  <link rel="sitemap" href="/sitemap-index.xml" />
</head>
```

#### Sitemap link in `robots.txt`

[Section titled “Sitemap link in robots.txt”](#sitemap-link-in-robotstxt)

If you have a `robots.txt` for your website, you can add the URL for the sitemap index to help crawlers:

public/robots.txt

```diff
User-agent: *
Allow: /


+Sitemap: https://<YOUR SITE>/sitemap-index.xml
```

If you want to reuse the `site` value from `astro.config.mjs`, you can also generate `robots.txt` dynamically. Instead of using a static file in the `public/` directory, create a `src/pages/robots.txt.ts` file and add the following code:

src/pages/robots.txt.ts

```ts
import type { APIRoute } from 'astro';


const getRobotsTxt = (sitemapURL: URL) => `\
User-agent: *
Allow: /


Sitemap: ${sitemapURL.href}
`;


export const GET: APIRoute = ({ site }) => {
  const sitemapURL = new URL('sitemap-index.xml', site);
  return new Response(getRobotsTxt(sitemapURL));
};
```

## Configuration

[Section titled “Configuration”](#configuration)

To configure this integration, pass an object to the `sitemap()` function in `astro.config.mjs`.

astro.config.mjs

```js
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  integrations: [
    sitemap({
      // configuration options
    }),
  ],
});
```

### `filter`

[Section titled “filter”](#filter)

**Type:** `(page: string) => boolean`

All pages are included in your sitemap by default. By adding a custom `filter` function, you can filter included pages by URL.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
      +filter: (page) => page !== 'https://example.com/secret-vip-lounge/',
    }),
  ],
});
```

The function will be called for every page on your site. The `page` function parameter is the full URL of the page currently under consideration, including your `site` domain. Return `true` to include the page in your sitemap, and `false` to leave it out.

To filter multiple pages, add arguments with target URLs.

astro.config.mjs

```js
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
      filter: (page) =>
        page !== 'https://example.com/secret-vip-lounge-1/' &&
        page !== 'https://example.com/secret-vip-lounge-2/' &&
        page !== 'https://example.com/secret-vip-lounge-3/' &&
        page !== 'https://example.com/secret-vip-lounge-4/',
    }),
  ],
});
```

### `customPages`

[Section titled “customPages”](#custompages)

**Type:** `string[]`

An array of externally-generated pages to be included in the generated sitemap file.

Use this option to include pages in your sitemap that are a part of your deployed site but are not created by Astro.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      customPages: ['https://example.com/external-page1', 'https://example.com/external-page2'],
    }),
  ],
});
```

### `customSitemaps`

[Section titled “customSitemaps”](#customsitemaps)

**Type:** `string[]`\
**Default:** `[]`

**Added in:** `@astrojs/sitemap@3.5.0`

An array of externally-generated sitemaps to be included in the `sitemap-index.xml` file along with the generated sitemap entries.

Use this option to include external sitemaps in the `sitemap-index.xml` file created by Astro for sections of your deployed site that have their own sitemaps not created by Astro. This is helpful when you host multiple services under the same domain.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      customSitemaps: ['https://example.com/blog/sitemap.xml', 'https://example.com/shop/sitemap.xml'],
    }),
  ],
});
```

### `entryLimit`

[Section titled “entryLimit”](#entrylimit)

**Type:** `number`\
**Default:** `45000`

The maximum number entries per sitemap file. The default value is 45000. A sitemap index and multiple sitemaps are created if you have more entries. See this [explanation of splitting up a large sitemap](https://developers.google.com/search/docs/advanced/sitemaps/large-sitemaps).

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      entryLimit: 10000,
    }),
  ],
});
```

### `changefreq`, `lastmod`, and `priority`

[Section titled “changefreq, lastmod, and priority”](#changefreq-lastmod-and-priority)

**Type:** `{ changefreq?: ChangeFreq; lastmod?: Date; priority?: number; }`

**Added in:** `@astrojs/sitemap@0.2.0`

These options correspond to the `<changefreq>`, `<lastmod>`, and `<priority>` tags in the [Sitemap XML specification.](https://www.sitemaps.org/protocol.html)

Note that `changefreq` and `priority` are ignored by Google.

Note

Due to limitations of Astro’s [Integration API](/en/reference/integrations-reference/), this integration can’t analyze a given page’s source code. This configuration option can set `changefreq`, `lastmod` and `priority` on a *site-wide* basis; see the next option **serialize** for how you can set these values on a per-page basis.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      changefreq: 'weekly',
+      priority: 0.7,
+      lastmod: new Date('2022-02-24'),
    }),
  ],
});
```

### `serialize`

[Section titled “serialize”](#serialize)

**Type:** `(item: SitemapItem) => SitemapItem | Promise<SitemapItem | undefined> | undefined`

A function called for each sitemap entry just before writing to a disk. This function can be asynchronous.

It receives as its parameter a `SitemapItem` object that can have these properties:

* `url` (absolute page URL). This is the only property that is guaranteed to be on `SitemapItem`.
* `changefreq`
* `lastmod` (ISO formatted date, `String` type)
* `priority`
* `links`.

This `links` property contains a `LinkItem` list of alternate pages including a parent page.

The `LinkItem` type has two fields: `url` (the fully-qualified URL for the version of this page for the specified language) and `lang` (a supported language code targeted by this version of the page).

The `serialize` function should return `SitemapItem`, touched or not.

The example below shows the ability to add sitemap specific properties individually.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
      +serialize(item) {
        +if (/exclude-from-sitemap/.test(item.url)) {
          +return undefined;
+        }
        +if (/your-special-page/.test(item.url)) {
          +item.changefreq = 'daily';
          +item.lastmod = new Date();
          +item.priority = 0.9;
+        }
        +return item;
+      },
    }),
  ],
});
```

### `chunks`

[Section titled “chunks”](#chunks)

**Type:** `Record<string, (item: SitemapItem) => SitemapItem | undefined>`

**Added in:** `@astrojs/sitemap@3.7.0` New

A map of functions that allows you to split your sitemap into multiple files based on custom logic. Each key in the object becomes the name of a separate sitemap file, and its corresponding function determines which URLs will be included in that chunk. This can be useful for instance if a specific section of your website changes very often and you’d like to specify a different change frequency for its entries.

Each chunk function receives a `SitemapItem` and for each item returns either:

* the modified `SitemapItem`, if the URL should be included in this chunk
* `undefined`, if the URL should not be included in this chunk

The example below shows how to split URLs into different sitemap files based on their path:

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      chunks: {
        +'blog': (item) => {
          +if (/blog/.test(item.url)) {
            +item.changefreq = 'weekly';
            +item.lastmod = new Date();
            +item.priority = 0.9;
            +return item;
+          }
+        },
        +'glossary': (item) => {
          +if (/glossary/.test(item.url)) {
            +item.changefreq = 'monthly';
            +item.lastmod = new Date();
            +item.priority = 0.7;
            +return item;
+          }
+        }
+      },
    }),
  ],
});
```

This configuration will generate the following files:

* `sitemap-blog-0.xml`
* `sitemap-glossary-0.xml`

URLs that don’t match any chunk will be placed in a default `sitemap-pages-0.xml` file.

### `i18n`

[Section titled “i18n”](#i18n)

**Type:** `{ defaultLocale: string; locales: Record<string, string>; }`

To [localize a sitemap](https://developers.google.com/search/docs/advanced/crawling/localized-versions#all-method-guidelines), pass an object to this `i18n` option.

This object has two required properties:

* `defaultLocale`: Its value must exist as one of `locales` keys.
* `locales`: key/value - pairs. The key is used to look for a locale part in a page path. The value is a [language attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/lang), only English alphabet and hyphen allowed.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      i18n: {
+        defaultLocale: 'en', // All urls that don't contain `es` or `fr` after `https://example.com/` will be treated as default locale, i.e. `en`
+        locales: {
+          en: 'en-US', // The `defaultLocale` value must present in `locales` keys
+          es: 'es-ES',
+          fr: 'fr-CA',
+        },
+      },
    }),
  ],
});
```

The resulting sitemap looks like this:

sitemap-0.xml

```xml
...
  <url>
    <loc>https://example.com/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://example.com/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://example.com/fr/"/>
  </url>
  <url>
    <loc>https://example.com/es/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://example.com/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://example.com/fr/"/>
  </url>
  <url>
    <loc>https://example.com/fr/</loc>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/"/>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://example.com/es/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://example.com/fr/"/>
  </url>
  <url>
    <loc>https://example.com/es/second-page/</loc>
    <xhtml:link rel="alternate" hreflang="es-ES" href="https://example.com/es/second-page/"/>
    <xhtml:link rel="alternate" hreflang="fr-CA" href="https://example.com/fr/second-page/"/>
    <xhtml:link rel="alternate" hreflang="en-US" href="https://example.com/second-page/"/>
  </url>
...
```

### `xslURL`

[Section titled “xslURL”](#xslurl)

**Type:** `string`

**Added in:** `@astrojs/sitemap@3.2.0`

The URL of an XSL stylesheet to style and prettify your sitemap.

The value set can be either a path relative to your configured `site` URL for a local stylesheet, or can be an absolute URL link to an external stylesheet.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      xslURL: '/sitemap.xsl'
    }),
  ],
});
```

### `filenameBase`

[Section titled “filenameBase”](#filenamebase)

**Type:** `string`\
**Default:** `sitemap`

**Added in:** `@astrojs/sitemap@3.4.0`

The name prefix string used when generating the sitemap XML files. The default value is `sitemap`.

This option may be useful when integrating an Astro site into a domain with preexisting sitemap files.

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      filenameBase: 'astronomy-sitemap'
    }),
  ],
});
```

The given configuration will generate sitemap files at `https://example.com/astronomy-sitemap-0.xml` and `https://example.com/astronomy-sitemap-index.xml`.

### `namespaces`

[Section titled “namespaces”](#namespaces)

**Type:** `{ news?: boolean; xhtml?: boolean; image?: boolean; video?: boolean; }`\
**Default:** `{ news: true, xhtml: true, image: true, video: true }`

**Added in:** `@astrojs/sitemap@3.6.0`

An object of XML namespaces to exclude from the generated sitemap.

Excluding unused namespaces can help create more focused sitemaps that are faster for search engines to parse and use less bandwidth. For example, if your site doesn’t have news content, videos, or multiple languages, you can exclude those namespaces to reduce XML bloat.

By default, all configurable namespaces (`news`, `xhtml`, `image`, and `video`) are included in your generated sitemap XML. To exclude one or more of these namespaces from your sitemap generation, add a `namespaces` configuration object and set individual options to `false`:

astro.config.mjs

```diff
import { defineConfig } from 'astro/config';
import sitemap from '@astrojs/sitemap';


export default defineConfig({
  site: 'https://example.com',
  integrations: [
    sitemap({
+      namespaces: {
+        news: false,
+        xhtml: false,
+      }
    })
  ]
});
```

## Examples

[Section titled “Examples”](#examples)

* The official Astro website uses Astro Sitemap to generate [its sitemap](https://astro.build/sitemap-index.xml).
* [Browse projects with Astro Sitemap on GitHub](https://github.com/search?q=%22%40astrojs%2Fsitemap%22+path%3Apackage.json\&type=Code) for more examples!