Generating a Sitemap for Your Site with NestJS
What a sitemap does
If a website were a museum, then its visitors—especially search engines—would use a map to understand how the place is laid out. A sitemap plays that role: it shows which pages exist, what kinds of resources they contain, and how those pieces fit together.
In more formal terms, a sitemap is a file that lists information about the pages, videos, and other files on a site, along with the relationships between them. Search engines such as Google read this file so they can crawl the site more efficiently. It also helps indicate which pages and files matter most and provides useful metadata for them.
How a sitemap is structured
A sitemap is an XML file containing a list of URLs from the site. Each URL entry can include several fields:
<loc>: the full URL of the page<lastmod>: the last modified time, optional<changefreq>: a suggested crawl frequency, optional<priority>: the relative importance of the page, from 0.0 to 1.0, optional
Planning a sitemap for your own site
For a purely static site, writing a sitemap by hand is usually manageable.
Once the site changes over time, though, manual maintenance becomes inconvenient very quickly. In that case, generating the sitemap through a backend endpoint is a much more practical approach.
A simple way to think about it is to divide the site into a few major sections. In this example, the site is organized around three key parts: the homepage, technical articles, and everything else.
- The homepage is the most important page because it is the main entry point to the site.
- Technical articles come next. Since articles are updated continuously, they should be pulled from the database and added dynamically when the sitemap is generated. If there are 10 articles, there should be 10 corresponding URL entries.
- Other pages cover less critical sections, such as life-related content, an about page, or an introduction to the website itself.
Generating the sitemap with NestJS
Install the library
npm install sitemap
Create a sitemap controller
import { Controller, Get, Header, Res } from '@nestjs/common';
import { Response } from 'express';
import { BlogService } from './blog.service';
@Controller()
export class SitemapController {
constructor(private readonly blogService: BlogService) {}
@Get('sitemap')
async getSitemap(@Res() res: Response): Promise<void> {
const sitemap = await this.blogService.generateSitemap();
res.setHeader('Content-Type', 'application/xml'); // 明确设置内容类型
res.status(200).send(sitemap); // 直接发送生成的 XML
}
}
This controller exposes a /sitemap route, calls the sitemap generation method, explicitly sets the response type to application/xml, and returns the generated XML directly.
Create the sitemap service
import { SitemapStream, streamToPromise } from 'sitemap';
// 站点地图
async generateSitemap(): Promise<string> {
const blogs = await this.findAllBlog({
type: '文章',
title: undefined,
content: undefined,
tag: undefined,
date: null,
star: undefined,
});
// 创建站点地图流
const sitemap = new SitemapStream({
hostname: 'https://flowersink.com',
});
// 静态页面
const staticPages = [
{ url: '/', changefreq: 'daily', priority: 1.0 },
{ url: '/blog/article', changefreq: 'weekly', priority: 0.8 },
{ url: '/blog/question', changefreq: 'weekly', priority: 0.8 },
{ url: '/blog/all', changefreq: 'weekly', priority: 0.8 },
{ url: '/life/heart', changefreq: 'monthly', priority: 0.7 },
{ url: '/about/me', changefreq: 'monthly', priority: 0.6 },
{ url: '/about/website', changefreq: 'monthly', priority: 0.6 },
{ url: '/about/message', changefreq: 'monthly', priority: 0.6 },
];
// 添加静态页面到站点地图
staticPages.forEach((page) => sitemap.write(page));
// 动态博客
blogs['blogs'].forEach((blog) => {
sitemap.write({
url: `/blog/${blog.id}`,
changefreq: 'weekly',
priority: blog.star ? 0.9 : 0.7,
lastmod: blog.date,
});
});
sitemap.end();
// 将站点地图转换为字符串
return streamToPromise(sitemap).then((data) => data.toString());
}
The logic here is straightforward:
- Query the article list from the database.
- Create a
SitemapStreamand set the site hostname. - Add a set of static pages, such as the homepage, article listing pages, life-related pages, and about pages.
- Loop through the blog records and append each article as a dynamic URL.
- Use
lastmodto include the article date. - Set a higher priority for starred articles, and a lower one for ordinary entries.
- Close the stream and convert the final sitemap into a string.
This keeps the sitemap aligned with the actual state of the site instead of relying on a manually maintained XML file.
Verify the result
Once the endpoint is in place, you can open the sitemap URL directly in the browser to confirm that the XML is being generated and returned correctly.