---
name: nuxtjs-sitemap
description: Generate, split, and debug XML sitemaps in a Nuxt app with the @nuxtjs/sitemap module. Use when a task mentions sitemap.xml, sitemap_index.xml, the sitemap config key, defineSitemapEventHandler, dynamic sitemap URLs from a CMS or API, multiple or chunked sitemaps, zeroRuntime, hreflang in sitemaps with @nuxtjs/i18n, defineSitemapSchema for Nuxt Content, or a page that is missing from or wrongly present in the sitemap.
license: MIT
compatibility: "Requires Node.js ^22.22.3 || ^24.15.0 || >=26.0.0. Requires Nuxt ^4.6.0 || ^5.0.0."
title: nuxtjs-sitemap
canonical_url: https://skilld.dev/gh/nuxt-modules/sitemap
last_updated: 2026-10-13T21:06:40.000Z
---

> Index of every page on this site: [llms.txt](https://skilld.dev/llms.txt)

> **Skill from skilld.dev.** Follow the user's requested action.
> If the user asked to fork this Skill, follow the fork workflow below. Do not execute the Skill instructions while copying it.
> Otherwise, follow the instructions below for this session. You do not need to install anything.
>
> Supporting files, fetch one when the Skill refers to it: [references/nuxt-content.md](https://skilld.dev/api/skills-raw/nuxt-modules/sitemap/nuxtjs-sitemap/references/nuxt-content.md).
>
> If the user asked to install this Skill, run `npx skilld install nuxt-modules/sitemap/nuxtjs-sitemap`. Install writes the Skill files into the project, so every session loads them.
>
> ## Fork workflow
>
> A fork creates an editable local Skill with its original author and licence. The request authorizes copying and local installation.
> 1. Check `./skills/nuxtjs-sitemap`, the project lockfile, and selected Agent targets together. If the local directory or installed Skill exists, stop. Never overwrite an existing directory or Agent target.
> 2. Read [source metadata](https://skilld.dev/api/v1/skills/nuxt-modules/sitemap/nuxtjs-sitemap) once. Use sourceUrl, sourceCommit, skillPath, sourceGone, and license. If the source is gone or its path is missing, stop. If license is null, read licence files at the source commit.
> 3. Fetch only the source commit into a temporary Git repository. Do not clone full history. Derive repository_url from sourceUrl, including repository renames. If sourceCommit is absent, resolve the sourceUrl ref once. Set source_commit to that actual commit. Run these commands in one shell call:
>
> ```sh
> git init --quiet "$temporary_dir"
> git -C "$temporary_dir" fetch --quiet --depth=1 "$repository_url" "$source_commit"
> git -C "$temporary_dir" checkout --quiet --detach FETCH_HEAD
> ```
>
> Read applicable licence declarations and notices at that commit. If copying is not permitted, report the restriction and stop.
> 4. Inspect source entries together, then copy the directory containing skillPath into `./skills/nuxtjs-sitemap`. Use the user's path if selected. Keep the original SKILL.md, relative links, scripts, binary assets, and executable modes. Exclude .git metadata. Reject symlinks and paths outside the Skill directory. After checking entries, use cp -a where available. A regular source directory needs no custom copy script. Do not save this page wrapper as SKILL.md.
> Preserve author credit, notices, and applicable licence files from repository or parent directories. Add PROVENANCE.md with the Skill page, source URL, actual commit, original path, and licence. Retain any existing PROVENANCE.md and record new provenance separately. Batch source inspection, copying, and provenance work where practical.
> 5. In the project root, run `skilld install ./skills/nuxtjs-sitemap --mode copy --plain`. If skilld is unavailable, use `npx skilld install ./skills/nuxtjs-sitemap --mode copy --plain`. This known command needs no help lookup. Install does not support --json. Use detected Agent targets, or add --agent for the targets the user selected. Install the local path, never the upstream selector. If installation fails, preserve the local copy and report the exact failure.
> 6. Confirm the local lockfile source and installed Agent copies once. Report the local path, actual commit, and Agent targets. After edits, reinstall the same local path. Upstream updates must not replace it. Do not publish or push unless the user asks.

# @nuxtjs/sitemap

Use Nuxt `^4.6.0 || ^5.0.0` and Node `^22.22.3 || ^24.15.0 || >=26.0.0`.
The module serves `/sitemap.xml`, built from app pages, route rules, prerendered routes, and your sources.
Docs: https://nuxtseo.com/docs/sitemap

## Setup

Install with `npx nuxt module add sitemap`. The config key is `sitemap`.
Included in `@nuxtjs/seo` v6. If the app uses `@nuxtjs/seo`, configure the `sitemap` key and do not add the module again.

Set `site.url`. Every `<loc>` resolves against it.
If `site.url` is missing, the production server uses the request `Host` header. The build gives no warning.
In dev, `<loc>` always uses the dev server host. This is expected.

If `@nuxtjs/robots` is installed, the module adds the sitemap to `robots.txt`. It uses `/sitemap_index.xml` when there are multiple sitemaps.

## Automatic behaviour

- Every static page is listed. Dynamic pages, such as `pages/blog/[slug].vue`, are not listed. Add them with a source.
- Prerendered routes are added, including routes the prerender crawler finds.
- A route with the `robots: false` route rule is dropped. So is a `robots` string with `noindex` or `none`.
- When a page is prerendered, `<img>` and `<video>` inside `<main>` become image and video entries. `article:modified_time` becomes `lastmod`.
- A content page gets `lastmod` from frontmatter: `sitemap.lastmod`, then a modification date (`updatedAt`, `modifiedAt`), then a publication date (`publishedAt`, `date`). `contentLastmod: false` turns this off.
- Entries are sorted by path depth, then alphabetically. Set `sortEntries: false` to keep source order.
- An invalid `lastmod` is dropped from the entry. Dev prints an XML comment in its place.
- In production, the resolved sitemap is cached for `cacheMaxAgeSeconds` (600 by default). Dev and prerender do not cache.

## Add dynamic URLs

Return the entries from a server route, then list the route in `sources`.
Import `defineSitemapEventHandler()` from `#sitemap/server`. Server auto imports also resolve it. It adds types only, no cache.

```ts
// server/api/__sitemap__/urls.ts
import { defineSitemapEventHandler } from '#sitemap/server'

export default defineSitemapEventHandler(async () => {
  const posts = await $fetch<{ slug: string, updatedAt: string }[]>('https://cms.example.com/posts')
  return posts.map(post => ({
    loc: `/blog/${post.slug}`, // a path; it resolves against site.url
    lastmod: post.updatedAt,
  }))
})
```

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  sitemap: {
    sources: ['/api/__sitemap__/urls'],
  },
})
```

A source can also be a remote JSON or XML URL, or `[url, { headers }]` for an authenticated API.
If a CMS returns encoded paths, set `_encoded: true` on each entry to stop double encoding.

`urls` in the config also adds entries, but the function runs once at build time. Use `sources` for data that changes after deploy.

## Remove or tune one page

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/checkout/**': { robots: false }, // drop from the sitemap
    '/legal': { sitemap: false }, // drop from the sitemap only
    '/about': { sitemap: { priority: 0.3, changefreq: 'yearly' } },
  },
  sitemap: {
    exclude: ['/admin/**', /^\/preview-/],
  },
})
```

`definePageMeta({ sitemap: { priority: 0.8 } })` sets values for that page. `definePageMeta({ sitemap: false })` removes it, also when it is prerendered.

## Multiple sitemaps

```ts
// nuxt.config.ts
export default defineNuxtConfig({
  sitemap: {
    sitemaps: {
      pages: { includeAppSources: true, exclude: ['/blog/**'] },
      posts: { sources: ['/api/__sitemap__/posts'], chunks: 5000 },
    },
  },
})
```

- The index is `/sitemap_index.xml`. On a server, `/sitemap.xml` redirects to it. A static build writes the index to `/sitemap.xml` as well.
- Child sitemaps are at `/__sitemap__/<name>.xml`. Chunks are `/__sitemap__/posts-0.xml`, `posts-1.xml`, and so on.
- `sitemapsPathPrefix: '/'` moves them to the root: `/pages.xml`, `/posts-0.xml`.
- App sources (pages, route rules, prerender) go only to a sitemap with `includeAppSources: true`.
- Top level `sources` also go only to sitemaps with `includeAppSources: true`.
- An entry with `_sitemap: 'posts'` goes only to that sitemap. An unknown name logs an error and drops the entry.
- `sitemaps: true` splits every URL into numbered chunks of `defaultSitemapsChunkSize` (1000).

## Prerender and zero runtime

To prerender the sitemap, add `/sitemap.xml` to `nitro.prerender.routes`. `nuxt generate` does this for you.
`zeroRuntime: true` prerenders every sitemap and removes the sitemap code from the server bundle.
In both modes, sources are fetched once at build. New CMS entries do not appear until the next build.

## Integrations

- Nuxt Content v3: a collection needs `defineSitemapSchema()` in its schema, or it is not in the sitemap. See [references/nuxt-content.md](https://skilld.dev/api/skills-raw/nuxt-modules/sitemap/nuxtjs-sitemap/references/nuxt-content.md).
- `@nuxtjs/i18n`: with a prefix strategy, each locale gets its own sitemap, with `hreflang` alternatives and `x-default`.
  The sitemap name is the locale `language` if it is set, else the locale `code`. With `language: 'en-US'`, the path is `/__sitemap__/en-US.xml`.
  A dynamic entry goes only to the default locale sitemap. Set `_i18nTransform: true` to add it to every locale with its prefix.
  `_sitemap` takes the sitemap name. `_sitemap: 'en'` fails when the sitemap is `en-US`.
  Set `autoI18n: false` for one sitemap without locales.

## Traps

- **String filters match whole path segments only.** `exclude: ['/blog/draft-*']` removes nothing. Use a RegExp such as `/^\/blog\/draft-/`.
- **A dynamic route is not in the sitemap** until a source, `urls`, or the prerender crawler provides its URLs.
- **A prerendered or `zeroRuntime` sitemap never refetches sources.** Use the runtime server for CMS data that changes between deploys.
- **Nuxt Content `filter` and `onUrl` cannot read outside variables.** The build fails and names the variable. See [references/nuxt-content.md](https://skilld.dev/api/skills-raw/nuxt-modules/sitemap/nuxtjs-sitemap/references/nuxt-content.md).
- **`lastmod` set to the current date on every build tells crawlers nothing.** Use a real content update time.

## Version limits

v9 has these breaking changes. Each line gives the fix.

- Nuxt `^4.6.0 || ^5.0.0` and Node `^22.22.3 || ^24.15.0 || >=26.0.0` are required. Upgrade both before the module.
- Hook contexts receive a `RequestEvent` from `nuxt/server`. `event.node.req` does not exist there. Read a header with `ctx.event.req.headers.get('authorization')`.
- `defineSitemapEventHandler()` receives a `RequestEvent` that is also typed as the server builder's `H3Event`. h3 helpers and utilities typed against `H3Event` accept it. `event.req` is the web `Request`.
- Import `defineSitemapEventHandler()` and `asSitemapUrl()` from `#sitemap/server`. Import `getQuery()` and other request utilities from `nuxt/server`.
- `@nuxtjs/robots` must be v7. `nuxt-site-config` must be v5. Upgrade them together with the sitemap.
- The optional `zod` peer is `^4.6.5`. Use Zod 4 with `defineSitemapSchema()`.
- Nuxt Content v2 is not supported. Upgrade to Nuxt Content v3 and add `defineSitemapSchema()` to each collection.
- The DevTools Sitemap tab needs the `nuxtseo-devtools-host` dev dependency.

## Config

- `sources`, `urls`, `include`, `exclude`, `defaults`: top level for one sitemap. With `sitemaps`, set them per sitemap.
- `excludeAppSources`: `true`, or names such as `['nuxt:pages', 'nuxt:prerender']`.
- `sitemapName` (`sitemap.xml`): the path of the single sitemap. Ignored with `sitemaps`.
- `cacheMaxAgeSeconds` (600): server cache and `Cache-Control`. `false` turns both off.
- `xsl` (`/__sitemap__/style.xsl`): the browser view. Set `false` for raw XML. Browsers show raw i18n XML as text; that is a browser bug.
- Other options: https://nuxtseo.com/docs/sitemap/api/config

Nitro hooks change output at runtime: `sitemap:sources` (add sources or request headers), `sitemap:input`, `sitemap:resolved`, `sitemap:output`, and `sitemap:sitemaps-resolved` (register sitemaps at runtime). See https://nuxtseo.com/docs/sitemap/nitro-api/nitro-hooks

## Debug

- `/__sitemap__/debug.json` lists every source, its URLs, and fetch errors. It exists in dev, or in production with `debug: true`. `zeroRuntime` removes it.
- Nuxt DevTools has a Sitemap tab with the same data. The tab needs `nuxtseo-devtools-host` as a dev dependency: `pnpm add -D nuxtseo-devtools-host`.
- For a prerendered sitemap, set `debug: true` and read `.output/public/__sitemap__/debug.json`.
