How to Generate Dynamic Sitemaps in Next.js

In this tutorial, you'll learn to generate your own sitemaps dynamically for your Next.js websites in only a few steps

Share:

Jul 29, 2023 359 Words

Read Time: 2 Minutes

How to Generate Dynamic Sitemaps in Next.js

Introduction

Let’s say you have folder containing markdown files which are used as individual blog posts in the Next.js blog website.

This is exactly what I did to generate sitemap.xml file for my Next.js website https://notionworkspaces.com/

Steps to generate sitemap.xml (only 3 steps)

  1. Create a sitemap.xml.js file inside src/pages/ folder from the Next.js home directory
  2. Add this code inside it
import fs from 'fs';
import matter from 'gray-matter';

const postsDirectory = path.join(process.cwd(), 'posts');

const URL = "https://yourwebsitedomain.com";

function generateSiteMap(posts) {
  return `<?xml version="1.0" encoding="UTF-8"?>
   <urlset xmlns="https://www.sitemaps.org/schemas/sitemap/0.9">
     <!-- Add the static URLs manually -->
     <url>
       <loc>${URL}</loc>
     </url>
     ${posts
       .map(({ id }) => {
         return `
           <url>
               <loc>${`${URL}/posts/${id}`}</loc>
               <lastmod>${new Date().toISOString()}</lastmod>
           </url>
         `;
       })
       .join("")}
   </urlset>
 `;
}

export function getSortedPostsData() {
  // Get file names under /posts
  const fileNames = fs.readdirSync(postsDirectory);
  const allPostsData = fileNames.map((fileName) => {
    // Remove ".md" from file name to get id
    const id = fileName.replace(/\.md$/, '');

    // Read markdown file as string
    const fullPath = path.join(postsDirectory, fileName);
    const fileContents = fs.readFileSync(fullPath, 'utf8');

    // Use gray-matter to parse the post metadata section
    const matterResult = matter(fileContents);

    // Combine the data with the id
    return {
      id,
      ...matterResult.data,
    };
  });
  // Filter out draft posts
  const livePosts = allPostsData.filter((postData) => {
    return postData.draft == false
  })
  // Sort posts by date
  return livePosts.sort((a, b) => {
    if (a.date < b.date) {
      return 1;
    } else {
      return -1;
    }
  });
}

export async function getServerSideProps({ res }) {
  const posts = getSortedPostsData();

  // Generate the XML sitemap with the blog data
  const sitemap = generateSiteMap(posts);

  res.setHeader("Content-Type", "text/xml");
  // Send the XML to the browser
  res.write(sitemap);
  res.end();

  return {
    props: {},
  };
}

export default function SiteMap() {}
  1. Run npm run dev locally to verify that the http://localhost:3000/sitemap.xml is created successfully.

That’s it!

Conclusion

You can deploy your Next.js app and verify the sitemap with all ‘posts’ links dynamically generated for you without any additional effort.

Your website’s sitemap should have the same structure as mine.

Here is how my sitemap looks → https://notionworkspaces.com/sitemap.xml

You can also modify the above code to add/delete parts that are unique to your blog.

I hope you found this useful!

👋 – @TnvMadhav

Find more posts from following topics

2024
accurate-requests
api-development
api-testing
api-testing-tools
array
automated-testing
bad-habits
base64-decoder
base64-encoder
binding
biography
blog
blogging
books
browser
bulma-css
bulma.io
button-swiftui
chatgpt
chrome
clipboard
code
code-block
code-navigation
code-snippet
codecoverage
comparison
compile
configuring-debugger-for-django-in-vs-code
configuring-launch.json-for-python-debugger
copy
copy-to-clipboard
copy-to-clipboard-neovim
css
current-date
current-time
current-timestamp
debugger-setup-in-visual-studio-code
debugging-django-app-in-visual-studio-code
debugging-python-code-in-visual-studio-code
debugging-python-programs-with-visual-studio-code
debugging-python-with-virtual-environment-in-vs-code
developer-productivity
developers
development-workflow
dom
dynamic-sitemap-in-nextjs
engineering-dashboard
enumerate
flowcharts
generics
git
git-diff
github
global-keyboard-shorcut
global-shortcut
go
go-hugo
go-programming
go-test
go-to-line
go-tool
go1.18
golang
golang-development
good-habits
gorilla-websocket
gpt
gpt-3.5
gpt-4
gpt-4-api
guide
gumroad
habits
habits-tracker-notion-template
hamburger-menu
hotkeys
html
hugo
ide
image
image-sharing
image-tool-for-ios
imagerenderer
include-timestamp
integrated-development-environment
ios
ios-16
ios16
javascript
jump-to-definition
keyboard-shortcut
leonardo-da-vinci
linux
ls
lsp
macos
map
markdown
markdown-code
mental-programming
menu
menubarextra
mergesort
mermaid-syntax
mistake-tracker-notion
mobile-view
modifier
modulo-operation
navbar
navigationlink
navigationstack
neovim
next.js
nextjs
nextjs-markdown
nextjs-sitemap
nextjs-sitemaps
nice-shot
nice-shot-pro
notion
notion-api
notion-api-python
notion-budget
notion-budget-template
notion-budget-tracker
notion-bug-report-tracker
notion-dashboard
notion-expense-manager
notion-habits
notion-habits-dashboard
notion-habits-template
notion-habits-tracker
notion-habits-tracker-template
notion-issue-tracker
notion-mistake-tracker
notion-product
notion-product-dashboard
notion-product-roadmap
notion-product-roadmap-dashboard
notion-tasks
notion-tasks-dashboard
notion-tasks-template
notion-tasks-tracker
notion-template
notionworkspaces
openai
osx
personal-ifttt-framework
photospicker
photospickeritem
phpickerfilter
postman-capabilities
postman-request
pre-request-script
product-roadmap-notion-template
product-roadmap-template
productivity
programming
python
python-api
python-debugger-tutorial-for-vs-code
python-debugging-mode-in-vs-code
python-notion-api
python3
reading
real-time-communication
rehype
remark
request-data
running-debugger-in-visual-studio-code
running-django-app-in-debugging-mode
running-program-in-debugging-mode-in-vs-code
running-python-code-in-debugging-mode
safari
screenshot-app-for-ios
screenshot-app-ios
screenshot-ios
screenshot-tool-for-ios
set-current-timestamp
setting-up-debugger-in-vs-code-for-python
share-extension
sharelink
sharepreview
sharesheet
simple-websocket-server
sitemap
slice
slices
slider
sort
sorting
space-complexity
step-by-step-guide
stocks-profits-tracker
stocks-profits-tracker-template
stocks-tracker
struct
sustained-vigilance
swift
swiftui
swiftui-button
swiftui-button-action
swiftui-button-style
table-of-contents
tasks-tracker-notion-template
test
testing
textfield-swiftui
til
tim-sort
time-complexity
timeliness
timestamp-integration
timsort
transferable
triggers-and-actions
tutorial
unittest
unix
us-stocks
usa-stocks
useful-ios-features
using-breakpoints-in-python-debugger
using-virtual-environment-with-python-debugger
vanilla-javascript
variable
vim
visual-mode
visual-studio-code
vs-code
vscode
vscode-go-to-line
walter-isaacson
web-sockets-in-go
websocket-client
websocket-programming
websocket-server
xcode
xss