Published on Monday, March 10, 2025
Next.js Sitemap Setup with next-sitemap
Posted by

Introduction
next-sitemap is a powerful package designed to automate the generation of sitemaps and robots.txt files in Next.js projects. This guide covers installation, configuration, and advanced options to optimize your SEO efforts effectively.
Installation
To install next-sitemap, run the following command:
npm install next-sitemap
Creating the Configuration File
next-sitemap requires a configuration file named next-sitemap.config.js in your project's root directory.
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: process.env.SITE_URL || 'https://example.com',
}
next-sitemap automatically loads environment variables from .env files.
Building Sitemaps
To generate sitemaps after building your project, update your package.json scripts:
{
"build": "next build",
"postbuild": "next-sitemap"
}
Custom Configuration File:
You can specify a custom configuration file using the --config flag:
{ "postbuild": "next-sitemap --config awesome.config.js" }
Using next-sitemap with PNPM
For PNPM users, create a .npmrc file in your project root with the following content:
enable-pre-post-scripts=true
Adding Additional Routes Manually
next-sitemap includes all routes by default, but you can use additionalPaths to add extra non-standard routes.
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: process.env.SITE_URL,
additionalPaths(config) {
const routes = [
"/blog/post-01",
"/channels/codifyblog",
"/users/codifyblog",
];
return routes.map((route) => ({
loc: `${config.siteUrl}${route}`,
lastmod: new Date().toISOString(),
changefreq: "daily",
priority: 1,
}));
}
};
Adding Dynamic Routes
For dynamic routes like app/blog/[slug]/page.tsx, you can create a sitemap like this:
import type { MetadataRoute } from "next";
type Post = {
slug: string;
updatedAt: Date;
}
async function getAllPosts(): Promise<Post[]> {
return [
{
slug: "hello-world",
updatedAt: new Date(),
},
{
slug: "another-post",
updatedAt: new Date(),
},
];
}
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const BASE_URL = process.env.SITE_BASE_URL || "http://exanmple.com";
const posts = await getAllPosts();
return posts.map((post) => {
return {
url: `${BASE_URL}/blog/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: "daily",
priority: 1.0,
};
});
}
Note:
To include the generated sitemap in your robots.txt, update your next-sitemap configuration like this:
/** @type {import('next-sitemap').IConfig} */
module.exports = {
robotsTxtOptions: {
additionalSitemaps: [
`${process.env.SITE_URL}/blog/sitemap.xml`,
]
}
};
Generating Robots.txt File
To generate a robots.txt file with custom rules and additional sitemaps, use the following configuration:
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'https://example.com',
generateRobotsTxt: true,
robotsTxtOptions: {
policies: [
{ userAgent: '*', allow: '/' },
{ userAgent: 'test-bot', allow: ['/path', '/path-2'] },
{ userAgent: 'black-listed-bot', disallow: ['/sub-path-1', '/path-2'] },
],
additionalSitemaps: [
'https://example.com/my-custom-sitemap-1.xml',
'https://example.com/my-custom-sitemap-2.xml',
'https://example.com/my-custom-sitemap-3.xml',
],
},
};
Above configuration will generate sitemaps based on your project and a robots.txt like this.
# *
User-agent: *
Allow: /
# test-bot
User-agent: test-bot
Allow: /path
Allow: /path-2
# black-listed-bot
User-agent: black-listed-bot
Disallow: /sub-path-1
Disallow: /path-2
# Host
Host: https://example.com
# Sitemaps
Sitemap: https://example.com/sitemap.xml # Index sitemap
Sitemap: https://example.com/my-custom-sitemap-1.xml
Sitemap: https://example.com/my-custom-sitemap-2.xml
Sitemap: https://example.com/my-custom-sitemap-3.xml
Full configuration example
Here's an example next-sitemap.config.js configuration with all options
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'https://example.com',
changefreq: 'daily',
priority: 0.7,
sitemapSize: 5000,
generateRobotsTxt: true,
exclude: ['/protected-page', '/awesome/secret-page'],
alternateRefs: [
{
href: 'https://es.example.com',
hreflang: 'es',
},
{
href: 'https://fr.example.com',
hreflang: 'fr',
},
],
// Default transformation function
transform: async (config, path) => {
return {
loc: path, // => this will be exported as http(s)://<config.siteUrl>/<path>
changefreq: config.changefreq,
priority: config.priority,
lastmod: config.autoLastmod ? new Date().toISOString() : undefined,
alternateRefs: config.alternateRefs ?? [],
}
},
additionalPaths: async (config) => [
await config.transform(config, '/additional-page'),
],
robotsTxtOptions: {
policies: [
{
userAgent: '*',
allow: '/',
},
{
userAgent: 'test-bot',
allow: ['/path', '/path-2'],
},
{
userAgent: 'black-listed-bot',
disallow: ['/sub-path-1', '/path-2'],
},
],
additionalSitemaps: [
'https://example.com/my-custom-sitemap-1.xml',
'https://example.com/my-custom-sitemap-2.xml',
'https://example.com/my-custom-sitemap-3.xml',
],
},
}
Ignore Generated Sitemap Files
To prevent committing generated sitemaps and robots.txt files, add the following lines to your .gitignore file:
# generated sitemaps (next-sitemap)
public/robots.txt
public/sitemap*.xml
This ensures your generated files are excluded from version control.
Conclusion
The next-sitemap package simplifies sitemap generation and enhances your site's SEO performance. With flexible options for customization, it's a must-have for any Next.js project aiming to improve search engine visibility.