---
title: "Sitemap Performance"
description: "Use the default cache engine to keep your sitemaps fast."
canonical_url: "https://nuxtseo.com/docs/sitemap/advanced/performance"
last_updated: "2026-09-02T15:02:25.852Z"
---

## Introduction

For apps with 100k+ pages, generating a sitemap can be a slow process. As robots will request your sitemap frequently, it's important to keep it fast.

Nuxt SEO provides a default cache engine to keep your sitemaps fast and recommendations on how to improve performance.

## Performance Recommendations

When dealing with many URLs that are being generated from an external API, the best option is to use the `sitemaps`
option to create [Named Sitemap Chunks](/docs/sitemap/guides/multi-sitemaps).

Each sitemap should contain its own `sources`. This allows other sitemaps to be generated without waiting for this request.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    sitemaps: {
      posts: {
        sources: [
          'https://api.something.com/urls'
        ]
      },
    },
  },
})
```

If you need to split this up further, you should consider chunking by the type and some pagination format. For example,
you can paginate by when posts were created.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    sitemaps: {
      posts2020: {
        sources: [
          'https://api.something.com/urls?filter[yearCreated]=2020'
        ]
      },
      posts2021: {
        sources: [
          'https://api.something.com/urls?filter[yearCreated]=2021'
        ]
      },
    },
  },
})
```

Additionally, you may want to consider the following experimental options that may help with performance:

- `experimentalStreaming`: Streams XML serialization in roughly 64 KB chunks instead of building the complete XML string in memory
- `experimentalCompression`: Streams gzip or deflate compression when the client supports it
- `experimentalWarmUp`: Creates the sitemaps when Nitro starts

To reduce peak XML serialization memory while retaining compressed responses, enable streaming and compression together:

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    experimentalStreaming: true,
    experimentalCompression: true,
  },
})
```

Streaming applies to dynamic XML serialization. URL source fetching, normalization, filtering, deduplication, sorting, and the `sitemap:resolved` hook finish before the first XML chunk. The resolved URL plan remains in memory. Prerendering and `zeroRuntime` produce static files instead.

Keep URL sources in their documented JSON formats. Streaming a source response does not make URL resolution incremental because the global processing stages require the complete URL plan.

When `cacheMaxAgeSeconds` is enabled in production, streaming caches this finalized URL plan with stale-while-revalidate. Source resolution and the `sitemap:resolved` hook run on cache misses and refreshes; XML serialization and optional compression remain pull-driven for each response.

The `sitemap:output` hook remains backwards compatible. If a hook reads or replaces `ctx.sitemap`, that response is buffered before being streamed to the client. Hooks that do not access `ctx.sitemap` keep the streaming serializer path.

A CDN, reverse proxy, or deployment adapter may buffer the response after Nuxt sends it. Verify behavior in the production path rather than relying on local timing alone.

### Verify the render mode

Enable `debug` temporarily and inspect `X-Sitemap-Render-Mode`:

- `stream`: XML serialization stayed pull driven
- `buffered-hook`: A `sitemap:output` hook accessed the XML string

A streamed response omits `Content-Length`. `Content-Encoding: gzip` or `deflate` confirms transport compression, but does not prove that XML serialization streamed.

**Very large sites (100k+ URLs).** For sites at this scale, two practices matter most:

1. **Set generous chunk sizes.** Search engines accept up to 50,000 URLs per file. The default `defaultSitemapsChunkSize` of 1000 generates 50× more chunks than necessary; bumping to `5000`–`50000` directly reduces total work and cache entries.
2. **Cache the source endpoint when the upstream is expensive.** [Sitemap Caching](#sitemap-caching) already keeps your `/api/*` sources off most requests. Add `defineCachedEventHandler` on top of that when the upstream API is slow, rate limited, or metered, or when several named sitemaps read the same endpoint. See [Which handler should I use?](/docs/sitemap/guides/dynamic-urls#which-handler-should-i-use).

With `cacheMaxAgeSeconds` enabled in production, chunks of the same base sitemap share one resolved URL computation per cache window, so chunking alone does not add source fetches. If caching is disabled, each requested chunk processes the complete base URL set before slicing its own URLs. Splitting one large sitemap into per-shard sitemaps, such as one per locale or content type, is still useful when shards have different cache lifetimes or sources.

## Zero Runtime Mode

If your sitemap URLs only change when you deploy (not at runtime), you can enable `zeroRuntime` to generate sitemaps at build time and eliminate sitemap generation code from your server bundle.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    zeroRuntime: true
  }
})
```

This reduces server bundle size by \~50KB. The sitemap is generated once at build time and served as a static file.

See the [Zero Runtime](/docs/sitemap/guides/zero-runtime) guide for details.

## Sitemap Caching

Caching your sitemap can help reduce the load on your server and improve performance.

By default, SWR caching is enabled on production environments and sitemaps will be cached for 10 minutes.

This is configured by overriding your route rules and leveraging the native Nuxt caching.

### Cache Time

You can change the cache time by setting the `cacheMaxAgeSeconds` option. This affects the `Cache-Control` header sent to browsers and search engines.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    cacheMaxAgeSeconds: 3600 // 1 hour
  }
})
```

If you want to disable caching, set `cacheMaxAgeSeconds` to `false` or `0`.

`cacheMaxAgeSeconds` controls both the HTTP `Cache-Control` header and the server-side SWR cache TTL. For high-volume sites, raising it to several hours significantly reduces origin load.

A common question here: does `defineSitemapEventHandler` cache my endpoint? No. The helper is just a typed event handler. The module caches what your endpoint returns — the resolved URL set and the rendered XML — so your endpoint only runs when that cache expires.

### Cache Driver

The cache engine is set to the Nitro default of the `cache/` path.

If you want to customize the cache engine, you can set the `runtimeCacheStorage` option.

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  sitemap: {
    // cloudflare kv binding example
    runtimeCacheStorage: {
      driver: 'cloudflare-kv-binding',
      binding: 'OG_IMAGE_CACHE'
    }
  }
})
```