sitemap.xml
sitemap.(xml|js|ts) is a special file that matches the Sitemaps XML format 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.
<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 type is available.
Good to know:
sitemap.jsis a special Route Handler that is cached by default unless it uses a Dynamic API or dynamic config option.
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, }, ] }Output:
<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.
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 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.
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 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
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', }, }, }, ] }Output:
<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.xmlandapp/products/sitemap.xml. - By using the
generateSitemapsfunction.
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.
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<number> }): 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, })) }Your generated sitemaps will be available at /.../sitemap/[id]. For example, /product/sitemap/1.xml.
See the generateSitemaps API reference for more information.
Returns
The default function exported from sitemap.(xml|ts|js) should return an array of objects with the following properties:
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 number. |
v14.2.0 | Add localizations support. |
v13.4.14 | Add changeFrequency and priority attributes to sitemaps. |
v13.3.0 | sitemap introduced. |
Next Steps
Was this helpful?