npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

next-dynamic-sitemap-generator

v1.0.1

Published

Automatically generate sitemap.xml and robots.txt for Next.js apps with support for dynamic routes and ISR

Readme

Next Dynamic Sitemap Generator

npm version License: MIT

Automatically generate sitemap.xml and robots.txt during build time or runtime for Next.js apps, with support for dynamic routes from both pages and app directories.

✨ Features

  • Auto-detect routes from pages and app directories
  • Dynamic route support (e.g., /blog/[slug])
  • Multiple sitemaps with index file (e.g., pages.xml, blog.xml, tags.xml)
  • Async dynamic paths via config function per sitemap
  • ISR/Revalidation support with API endpoint
  • TypeScript support with full type definitions
  • Lightweight (<10kb, zero dependencies)
  • CLI tool for build integration
  • Customizable priorities, change frequencies, and exclusions per sitemap

🚀 Installation

npm install next-dynamic-sitemap-generator
# or
yarn add next-dynamic-sitemap-generator

📁 Examples

Check out the examples/ directory for different usage patterns:

  • examples/simple/ - Basic single sitemap setup
  • examples/complete-backup/ - Full-featured multiple sitemaps example

📖 Basic Usage

1. Create Configuration

Create sitemap.config.js in your project root:

/** @type {import('next-dynamic-sitemap-generator').SitemapConfig} */
module.exports = {
  siteUrl: 'https://example.com',
  changefreq: 'daily',
  priority: 0.7,

  // Optional: dynamically fetch slugs
  dynamicPaths: async () => {
    const res = await fetch('https://api.example.com/posts');
    const posts = await res.json();
    return posts.map(p => `/blog/${p.slug}`);
  },
};

2. Add to Build Script

Update your package.json:

{
  "scripts": {
    "build": "next build && next-dynamic-sitemap-generator"
  }
}

3. Build Your App

npm run build

This generates:

  • public/sitemap.xml
  • public/robots.txt

📄 Multiple Sitemaps

For larger websites, you can generate multiple sitemaps with an index file:

/** @type {import('next-dynamic-sitemap-generator').SitemapConfig} */
module.exports = {
  siteUrl: 'https://example.com',

  // Define multiple sitemaps
  sitemaps: [
    {
      id: 'pages',
      changefreq: 'weekly',
      priority: 0.8,
      // Include only static pages
      includeRoutes: ['/', '/about', '/contact'],
      exclude: ['/admin/**', '/api/**'],
    },
    {
      id: 'blog',
      changefreq: 'daily',
      priority: 0.7,
      // Include only blog routes
      includeRoutes: ['/blog/**'],
      // Dynamic blog posts
      dynamicPaths: async () => {
        const posts = await fetch('https://api.example.com/posts').then(r => r.json());
        return posts.map(post => `/blog/${post.slug}`);
      },
    },
    {
      id: 'products',
      changefreq: 'weekly',
      priority: 0.6,
      // Dynamic product pages
      dynamicPaths: async () => {
        const products = await fetch('https://api.example.com/products').then(r => r.json());
        return products.map(product => `/products/${product.id}`);
      },
      additionalUrls: [
        { loc: '/products', changefreq: 'monthly', priority: 0.9 },
      ],
    },
  ],
};

This generates:

  • public/sitemap.xml (index file)
  • public/pages.xml (static pages)
  • public/blog.xml (blog posts)
  • public/products.xml (product pages)
  • public/robots.txt

🔧 Advanced Configuration

Dynamic Paths with API

/** @type {import('next-dynamic-sitemap-generator').SitemapConfig} */
module.exports = {
  siteUrl: 'https://example.com',
  changefreq: 'weekly',
  priority: 0.8,

  // Fetch dynamic blog posts
  dynamicPaths: async () => {
    const posts = await fetch('https://api.example.com/posts').then(r => r.json());
    return posts.map(post => `/blog/${post.slug}`);
  },

  // Exclude certain routes
  exclude: ['/admin/**', '/api/**', '/_next/**'],

  // Add custom URLs
  additionalUrls: [
    {
      loc: '/special-page',
      changefreq: 'monthly',
      priority: 0.9,
    }
  ],

  // Transform URLs (e.g., add lastmod)
  transformUrl: (url) => ({
    ...url,
    lastmod: new Date().toISOString().split('T')[0],
  }),

  // Custom robots.txt
  robotsTxt: `User-agent: *
Allow: /

Disallow: /admin/
Disallow: /api/

Sitemap: https://example.com/sitemap.xml`,
};

API Route for Rebuilding

Create /pages/api/rebuild-sitemap.js (or /app/api/rebuild-sitemap/route.js):

import { generateSitemap } from 'next-dynamic-sitemap-generator';

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  try {
    const result = await generateSitemap();
    res.status(200).json({
      success: true,
      sitemapPath: result.sitemapPath,
      urlCount: result.urlCount,
    });
  } catch (error) {
    res.status(500).json({ error: error.message });
  }
}

Trigger rebuild after CMS updates:

curl -X POST https://yourdomain.com/api/rebuild-sitemap

🛠️ CLI Options

next-dynamic-sitemap-generator [options]

Options:
  -c, --config <path>     Path to config file (default: sitemap.config.js)
  -o, --output <dir>      Output directory (default: public)
  --no-robots            Skip generating robots.txt
  -v, --verbose          Enable verbose output
  -h, --help             Show help

Examples:
  next-dynamic-sitemap-generator
  next-dynamic-sitemap-generator --config ./config/sitemap.js --output ./dist
  next-dynamic-sitemap-generator --no-robots --verbose

📁 Configuration Reference

SitemapConfig

| Property | Type | Default | Description | |----------|------|---------|-------------| | siteUrl | string | Required | Base URL of your site | | changefreq | ChangeFrequency | 'daily' | Default change frequency | | priority | number | 0.7 | Default priority (0.0-1.0) | | dynamicPaths | () => Promise<string[]> \| string[] | undefined | Function to fetch dynamic paths | | exclude | string[] | [] | Patterns to exclude from sitemap | | additionalUrls | SitemapUrl[] | [] | Additional URLs to include | | transformUrl | (url: SitemapUrl) => SitemapUrl \| null | undefined | Transform function for URLs | | includeRoot | boolean | true | Include root path / | | robotsTxt | string | undefined | Custom robots.txt content | | sitemaps | SitemapDefinition[] | undefined | Multiple sitemap definitions |

SitemapDefinition

| Property | Type | Default | Description | |----------|------|---------|-------------| | id | string | Required | Unique identifier (used in filename) | | changefreq | ChangeFrequency | config.changefreq | Change frequency for this sitemap | | priority | number | config.priority | Priority for this sitemap (0.0-1.0) | | dynamicPaths | () => Promise<string[]> \| string[] | config.dynamicPaths | Function to fetch dynamic paths | | exclude | string[] | config.exclude | Patterns to exclude | | additionalUrls | SitemapUrl[] | config.additionalUrls | Additional URLs to include | | transformUrl | (url: SitemapUrl) => SitemapUrl \| null | config.transformUrl | Transform function for URLs | | includeRoot | boolean | config.includeRoot | Include root path / | | includeRoutes | string[] | undefined | Route patterns to include (e.g., ['/blog/**']) |

ChangeFrequency

  • 'always'
  • 'hourly'
  • 'daily'
  • 'weekly'
  • 'monthly'
  • 'yearly'
  • 'never'

📄 Generated Files

Single Sitemap

sitemap.xml

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
    <changefreq>daily</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://example.com/blog/hello-world</loc>
    <changefreq>daily</changefreq>
    <priority>0.7</priority>
  </url>
</urlset>

Multiple Sitemaps

sitemap.xml (Index)

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://example.com/pages.xml</loc>
    <lastmod>2025-01-06T10:30:00.000Z</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://example.com/blog.xml</loc>
    <lastmod>2025-01-06T10:30:00.000Z</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://example.com/products.xml</loc>
    <lastmod>2025-01-06T10:30:00.000Z</lastmod>
  </sitemap>
</sitemapindex>

pages.xml

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
    <changefreq>weekly</changefreq>
    <priority>1.0</priority>
  </url>
  <url>
    <loc>https://example.com/about</loc>
    <changefreq>weekly</changefreq>
    <priority>0.8</priority>
  </url>
</urlset>

robots.txt

User-agent: *
Allow: /

Sitemap: https://example.com/sitemap.xml

🔍 Route Detection

The package automatically detects routes from:

  • pages/ directory (Next.js 12 and below)
  • app/ directory (Next.js 13+)
  • src/pages/ directory
  • src/app/ directory

It supports:

  • Static routes: pages/about.js/about
  • Dynamic routes: pages/blog/[slug].js/blog/[slug]
  • Nested routes: pages/blog/category/[slug].js/blog/category/[slug]
  • Index routes: pages/index.js/

🏗️ Programmatic Usage

import { generateSitemap, SitemapGenerator } from 'next-dynamic-sitemap-generator';

// Simple generation
const result = await generateSitemap({
  configPath: './sitemap.config.js',
  outputDir: 'public',
  generateRobotsTxt: true,
});

// Advanced usage with custom generator
const generator = new SitemapGenerator('./my-project');
const result = await generator.generate({
  configPath: './config/sitemap.js',
  outputDir: './dist',
});

🤝 Integration Examples

With Content Management Systems

// sitemap.config.js
module.exports = {
  siteUrl: 'https://example.com',
  dynamicPaths: async () => {
    // Fetch from CMS API
    const posts = await fetch('https://cms.example.com/api/posts').then(r => r.json());
    const products = await fetch('https://cms.example.com/api/products').then(r => r.json());

    return [
      ...posts.map(p => `/blog/${p.slug}`),
      ...products.map(p => `/products/${p.slug}`),
    ];
  },
};

With Webhooks

// /pages/api/webhook.js
import { generateSitemap } from 'next-dynamic-sitemap-generator';

export default async function handler(req, res) {
  if (req.method === 'POST') {
    // Verify webhook signature (implement your own verification)

    // Regenerate sitemap after content update
    try {
      await generateSitemap();
      res.status(200).json({ success: true });
    } catch (error) {
      res.status(500).json({ error: error.message });
    }
  } else {
    res.status(405).json({ error: 'Method not allowed' });
  }
}

🚨 Requirements

  • Node.js: >= 16.0.0
  • Next.js: >= 15.0.0
  • TypeScript: >= 4.0.0 (for TypeScript projects)

📦 Bundle Size

  • Minified: ~8.5kb
  • Gzipped: ~2.8kb
  • Dependencies: 0 (uses only Node.js built-ins)

🤝 Contributing

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

📄 License

MIT © Parsa Jiravand

🙏 Acknowledgments

Inspired by the need for lightweight, dynamic sitemap generation in Next.js applications. Special thanks to the Next.js community for their excellent documentation and tooling.