10 minutes read

Generate a Dynamic Sitemap for Next JS

Summary:Next JS does not have inbuilt support to generate a dynamic sitemap. In this tutorial, we will look into multiple ways to build a dynamic sitemap with Next JS easily.

SEO and speed are the primary reasons why we prefer Next JS.

Talking about the SEO Next JS doesn't have inbuilt sitemap feature. But we can easily generate a dynamic sitemap in many ways using the features it provides.

There are two different ways to generate a sitemap in Next JS.

  • Using a script to generate sitemap at build time
  • Using Next JS lambda functions or a backend server to send a dynamic sitemap

Out of these two, the first one (using script) is not dynamic as it will change only when new build occurs. The second option is dynamic and useful to us.

Using a Script to Generate Sitemap at Build time

This is the easiest solution to build a sitemap in Next JS. The only disadvantage is that it is not dynamic, it will change only at the build time.

Using a script to generate a sitemap in Next JS is the best solution if your site doesn’t have any dynamic data.

For example, you are building a blog with markdown files. In that case, the website updates with a new build and a new sitemap is generated.

The process is very simple and I have explained them in steps.

  • Find all files inside the pages folder which needs to be included in sitemap and read their filenames (because Next JS has file-based routing so their filename is slug). In scripts/generateSitemap.js
const fs = require("fs");
const globby = require("globby");

(async () => {
  const pages = await globby(["pages/post/**/*{.js,.mdx}"]);
  const sitemap = `<?xml version="1.0"?>
		      <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
			   ${pages.map((page) => {
			      const path = page
			          .replace("pages", "")
				  .replace(".js", "")
				  .replace("/index", "")
				  .replace(".mdx", "");
				  const route = path === "/index" ? "" : path;

				return `
					<url>
					    <loc>${`https://YOURDOMIAN.com${route}/`}</loc>
					</url>
				    `;
			      })
			      .join("")}
			</urlset>`;

  fs.writeFileSync("public/sitemap.xml", sitemap);
})();
  • The second step is to run this script at each new build. We can use Next JS config (next.config.js) file for that.
module.exports = {
  webpack: (config, { isServer }) => {
    if (isServer) {
      require("./scripts/generateSitemap.js");
      console.log("Generating the Sitemap");
    }

    return config;
  },
};

Finished. Now your new sitemap will be placed at public/sitemap.xml . It will be updated at each new build.

Using Next JS Lambda Functions or Your own Server

Next JS lambda functions are very useful in handling data from external sources. We can build a dynamic sitemap for Next JS each time with a new request.

It is very useful for blogs and e-commerce sites which are dynamic and update frequently.

The flow is very simple, we fetch the data and generate a new sitemap with each request.

Here is the complete step by step explanation of the process.

  • Fetch the data and generate a sitemap. In pages/api/sitemap.js
const builder = require("xmlbuilder");

export default (req, res) => {
  try {
    //Get all the data to generate dynamic sitemap
    const allPublishedPosts = getAllPublishedPosts();
    //Generate Sitemap
    var newbuilder = builder
      .begin()
      .i("xml-stylesheet", 'type="text/xsl" href="/sitemap.xsl"')
      .dec("1.0", "UTF-8", true);
    var root = newbuilder.node("urlset");
    root.att("xmlns", "http://www.sitemaps.org/schemas/sitemap/0.9");
    allPublishedPosts.forEach((element) => {
      var url = root.ele("url");
      url.ele("loc", `https://YOURDOMAIN.com/${element.slug}/`)
      url.ele("lastmod", `${new Date(element.updated_at).toISOString()}`)
      url.ele("changefreq", `monthly`);
      url.ele("priority", `0.8`);
    });
    var xml = root.end({ pretty: true });
    res.statusCode = 200
    //Set appropriate header
    res.setHeader("Content-Type", "text/xml");
    res.send(xml);
  } catch (error) {
    logger.error(error);
    res.status(500).send({ message: "Server Error" });
  }
}
  • The second step will be to rewrite /sitemap.xml to /api/sitemap so that our sitemap will be accessible at https://YOURDOMAIN.com/sitemap.xml. In next.config.js.
async rewrites() {
    return [
      {
        source: "/sitemap.xml",
        destination: "/api/sitemap/",
      },
    ];
  },

Now, you can see your sitemap at /sitemap.xml which will be dynamically generated by Next JS lambda function.

If you are using a separate server then you can also do the sitemap generation part of the server itself and use Next JS to fetch sitemap instead of raw data.

Conclusion

These were the two very useful ways to generate a dynamic sitemap in Next JS. To summarise I will add two points here.

  • Use scripts to build sitemap if data is based on files in Next JS and you are not using any external data.
  • For external and frequently changing data, you can use Lambda functions to generate a dynamic sitemap in Next JS.

There are high chances that these two solutions are fit for all sitemap problems in Next JS. If you face any other problem, please use the comment section for that.