UNPKG

next

Version:

The React Framework

427 lines (378 loc) • 11.6 kB
--- title: sitemap.xml description: API Reference for the sitemap.xml file. related: title: Next Steps description: Learn how to use the generateSitemaps function. links: - app/api-reference/functions/generate-sitemaps --- `sitemap.(xml|js|ts)` is a special file that matches the [Sitemaps XML format](https://www.sitemaps.org/protocol.html) to help search engine crawlers index your site more efficiently. ### Sitemap files (.xml) For smaller applications, you can create a `sitemap.xml` file and place it in the root of your `app` directory. ```xml filename="app/sitemap.xml" <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://acme.com</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>yearly</changefreq> <priority>1</priority> </url> <url> <loc>https://acme.com/about</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>monthly</changefreq> <priority>0.8</priority> </url> <url> <loc>https://acme.com/blog</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> </urlset> ``` ### Generating a sitemap using code (.js, .ts) You can use the `sitemap.(js|ts)` file convention to programmatically **generate** a sitemap by exporting a default function that returns an array of URLs. If using TypeScript, a [`Sitemap`](#returns) type is available. > **Good to know**: `sitemap.js` is a special Route Handler that is cached by default unless it uses a [Request-time API](/docs/app/glossary#request-time-apis) or [dynamic config](/docs/app/guides/caching-without-cache-components#dynamic) option. ```ts filename="app/sitemap.ts" switcher import type { MetadataRoute } from 'next' export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://acme.com', lastModified: new Date(), changeFrequency: 'yearly', priority: 1, }, { url: 'https://acme.com/about', lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8, }, { url: 'https://acme.com/blog', lastModified: new Date(), changeFrequency: 'weekly', priority: 0.5, }, ] } ``` ```js filename="app/sitemap.js" switcher export default function sitemap() { return [ { url: 'https://acme.com', lastModified: new Date(), changeFrequency: 'yearly', priority: 1, }, { url: 'https://acme.com/about', lastModified: new Date(), changeFrequency: 'monthly', priority: 0.8, }, { url: 'https://acme.com/blog', lastModified: new Date(), changeFrequency: 'weekly', priority: 0.5, }, ] } ``` Output: ```xml filename="acme.com/sitemap.xml" <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> <url> <loc>https://acme.com</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>yearly</changefreq> <priority>1</priority> </url> <url> <loc>https://acme.com/about</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>monthly</changefreq> <priority>0.8</priority> </url> <url> <loc>https://acme.com/blog</loc> <lastmod>2023-04-06T15:02:24.021Z</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> </urlset> ``` ### Image Sitemaps You can use `images` property to create image sitemaps. Learn more details in the [Google Developer Docs](https://developers.google.com/search/docs/crawling-indexing/sitemaps/image-sitemaps). ```ts filename="app/sitemap.ts" switcher import type { MetadataRoute } from 'next' export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://example.com', lastModified: '2021-01-01', changeFrequency: 'weekly', priority: 0.5, images: ['https://example.com/image.jpg'], }, ] } ``` Output: ```xml filename="acme.com/sitemap.xml" <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:image="http://www.google.com/schemas/sitemap-image/1.1" > <url> <loc>https://example.com</loc> <image:image> <image:loc>https://example.com/image.jpg</image:loc> </image:image> <lastmod>2021-01-01</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> </urlset> ``` ### Video Sitemaps You can use `videos` property to create video sitemaps. Learn more details in the [Google Developer Docs](https://developers.google.com/search/docs/crawling-indexing/sitemaps/video-sitemaps). ```ts filename="app/sitemap.ts" switcher import type { MetadataRoute } from 'next' export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://example.com', lastModified: '2021-01-01', changeFrequency: 'weekly', priority: 0.5, videos: [ { title: 'example', thumbnail_loc: 'https://example.com/image.jpg', description: 'this is the description', }, ], }, ] } ``` Output: ```xml filename="acme.com/sitemap.xml" <?xml version="1.0" encoding="UTF-8"?> <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:video="http://www.google.com/schemas/sitemap-video/1.1" > <url> <loc>https://example.com</loc> <video:video> <video:title>example</video:title> <video:thumbnail_loc>https://example.com/image.jpg</video:thumbnail_loc> <video:description>this is the description</video:description> </video:video> <lastmod>2021-01-01</lastmod> <changefreq>weekly</changefreq> <priority>0.5</priority> </url> </urlset> ``` ### Generate a localized Sitemap ```ts filename="app/sitemap.ts" switcher import type { MetadataRoute } from 'next' export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://acme.com', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es', de: 'https://acme.com/de', }, }, }, { url: 'https://acme.com/about', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es/about', de: 'https://acme.com/de/about', }, }, }, { url: 'https://acme.com/blog', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es/blog', de: 'https://acme.com/de/blog', }, }, }, ] } ``` ```js filename="app/sitemap.js" switcher export default function sitemap() { return [ { url: 'https://acme.com', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es', de: 'https://acme.com/de', }, }, }, { url: 'https://acme.com/about', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es/about', de: 'https://acme.com/de/about', }, }, }, { url: 'https://acme.com/blog', lastModified: new Date(), alternates: { languages: { es: 'https://acme.com/es/blog', de: 'https://acme.com/de/blog', }, }, }, ] } ``` Output: ```xml filename="acme.com/sitemap.xml" <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml"> <url> <loc>https://acme.com</loc> <xhtml:link rel="alternate" hreflang="es" href="https://acme.com/es"/> <xhtml:link rel="alternate" hreflang="de" href="https://acme.com/de"/> <lastmod>2023-04-06T15:02:24.021Z</lastmod> </url> <url> <loc>https://acme.com/about</loc> <xhtml:link rel="alternate" hreflang="es" href="https://acme.com/es/about"/> <xhtml:link rel="alternate" hreflang="de" href="https://acme.com/de/about"/> <lastmod>2023-04-06T15:02:24.021Z</lastmod> </url> <url> <loc>https://acme.com/blog</loc> <xhtml:link rel="alternate" hreflang="es" href="https://acme.com/es/blog"/> <xhtml:link rel="alternate" hreflang="de" href="https://acme.com/de/blog"/> <lastmod>2023-04-06T15:02:24.021Z</lastmod> </url> </urlset> ``` ### Generating multiple sitemaps While a single sitemap will work for most applications. For large web applications, you may need to split a sitemap into multiple files. There are two ways you can create multiple sitemaps: - By nesting `sitemap.(xml|js|ts)` inside multiple route segments e.g. `app/sitemap.xml` and `app/products/sitemap.xml`. - By using the [`generateSitemaps`](/docs/app/api-reference/functions/generate-sitemaps) function. For example, to split a sitemap using `generateSitemaps`, return an array of objects with the sitemap `id`. Then, use the `id` to generate the unique sitemaps. ```ts filename="app/product/sitemap.ts" switcher import type { MetadataRoute } from 'next' import { BASE_URL } from '@/app/lib/constants' export async function generateSitemaps() { // Fetch the total number of products and calculate the number of sitemaps needed return [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }] } export default async function sitemap(props: { id: Promise<string> }): Promise<MetadataRoute.Sitemap> { const id = await props.id // Google's limit is 50,000 URLs per sitemap const start = id * 50000 const end = start + 50000 const products = await getProducts( `SELECT id, date FROM products WHERE id BETWEEN ${start} AND ${end}` ) return products.map((product) => ({ url: `${BASE_URL}/product/${product.id}`, lastModified: product.date, })) } ``` ```js filename="app/product/sitemap.js" switcher import { BASE_URL } from '@/app/lib/constants' export async function generateSitemaps() { // Fetch the total number of products and calculate the number of sitemaps needed return [{ id: 0 }, { id: 1 }, { id: 2 }, { id: 3 }] } export default async function sitemap(props) { const id = await props.id // Google's limit is 50,000 URLs per sitemap const start = id * 50000 const end = start + 50000 const products = await getProducts( `SELECT id, date FROM products WHERE id BETWEEN ${start} AND ${end}` ) return products.map((product) => ({ url: `${BASE_URL}/product/${product.id}`, lastModified: product.date, })) } ``` Your generated sitemaps will be available at `/.../sitemap/[id]`. For example, `/product/sitemap/1.xml`. See the [`generateSitemaps` API reference](/docs/app/api-reference/functions/generate-sitemaps) for more information. ## Returns The default function exported from `sitemap.(xml|ts|js)` should return an array of objects with the following properties: ```tsx type Sitemap = Array<{ url: string lastModified?: string | Date changeFrequency?: | 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never' priority?: number alternates?: { languages?: Languages<string> } }> ``` ## Version History | Version | Changes | | ---------- | ------------------------------------------------------------ | | `v16.0.0` | `id` is now a promise that resolves to a `string`. | | `v14.2.0` | Add localizations support. | | `v13.4.14` | Add `changeFrequency` and `priority` attributes to sitemaps. | | `v13.3.0` | `sitemap` introduced. |