NextJS 동적 sitemap 생성하기
- 현재 블로그는 NextJS로 빌드되어 Google Console에 등록되어 있습니다.
- Google Console에 sitemap을 등록하기 위해 React에서 했던 것처럼 다음과 같이 sitemap을 손쉽게 만들어주는 xml-sitemaps을 사용해 만들었습니다.
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<!-- created with Free Online Sitemap Generator www.xml-sitemaps.com -->
<url>
<loc>https://seunghyunlim.vercel.app/</loc>
<lastmod>2025-01-22T00:20:55+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<loc>https://seunghyunlim.vercel.app/posts</loc>
<lastmod>2025-01-22T00:20:55+00:00</lastmod>
<priority>0.80</priority>
</url>
…..
</urlset>
문제 상황
- 블로그 글을 추가할 때마다 직접 sitemap.xml을 수정해야 했습니다.
- 또한, 실수로 sitemap.xml에 블로그 글이 누락되거나 잘못된 url을 작성할 경우 검색엔진 크롤러가 인식하지 못할 수 있습니다.
- 유지보수가 힘들고 무엇보다 귀찮습니다..
이러한 문제를 해결하기 위해 동적으로 sitemap을 생성하는 방법을 찾아보다, Next.js에서 자체적으로 지원하는 동적 sitemap 기능을 발견해 이를 적용해 보았습니다.
Next.js의 MetadataRoute.Sitemap으로 동적 sitemap 생성
- 동적 sitemap을 생성하기 위해 Next.js sitemap.xml 문서를 참고했습니다.
- 공식문서에 나와있는 예제는 다음과 같습니다.
import type { MetadataRoute } from 'next'
export default function sitemap(): MetadataRoute.Sitemap {
return [
{
url: 'https://acme.com',
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 1,
},
{
url: 'https://acme.com/about',
lastModified: new Date(),
changeFrequency: 'monthly',
priority: 0.8,
},
{
url: 'https://acme.com/blog',
lastModified: new Date(),
changeFrequency: 'weekly',
priority: 0.5,
},
]
}
- 먼저 sitemap.xml 파일을 sitemap.ts 파일로 변경 후, MetadataRoute.Sitemap이라는 타입으로 반환하면 됩니다.
- MetadataRoute.Sitemap의 소스코드는 다음과 같습니다.
type SitemapFile = Array<{
url: string;
lastModified?: string | Date;
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never';
priority?: number;
alternates?: {
languages?: Languages<string>;
};
}>;
declare namespace MetadataRoute {
type Robots = RobotsFile;
type Sitemap = SitemapFile;
type Manifest = ManifestFile;
}
- MetadataRoute를 보니 sitemap 말고도 Robots, Manifest도 동적으로 생성할 수 있는것 같은데 저는 sitemap만 생성할거니 다른건 다루지 않겠습니다.
- SitemapFile 타입은 위와 같은 구조를 가지고 있는데 각 필드는 다음과 같습니다.
- url: string
- 해당 페이지의 절대 경로 URL
- lastModified?: string | Date
- 페이지가 마지막으로 수정된 날짜
- hangeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
- 페이지가 얼마나 자주 변경되는지
- 크롤러가 어떤 주기마다 크롤링할지 결정합니다.
- priority?: number
- 0.0 ~ 1.0 사이의 숫자로 페이지의 중요도를 나타냅니다.
- 검색 엔진이 어떤 페이지를 우선적으로 크롤링할지 판단합니다.
- 보통은 중요한 페이지는 1.0, 일반적인 글은 0.8, 중요도가 낮은 페이지는 0.3 로 설정합니다.
- alternates?: { languages?: Languages<string> }
- 다국어 지원하는 경우 사용
- 특정 페이지의 다른 언어 버전을 지정할 때 활용
sitemap 적용
- 제 블로그는 contentlayer 라이브러리를 통해 md파일을 파싱하고 있습니다.
- contentlayer로 모든 post를 가져와 위와 같은 형식으로 반환하면 됩니다.
import type { MetadataRoute } from 'next'
import { allPosts } from '@/.contentlayer/generated'
export default function sitemap(): MetadataRoute.Sitemap {
return allPosts.map(post => ({
url: post.url,
lastModified: post.date,
changeFrequency: "weekly",
priority: 0.8,
}));
}
- 이제 test.md 파일을 만들고 /sitemap.xml로 들어가보면 아래와 같이 sitemap이 생성된걸 확인할 수 있습니다.

결론
- 이제 블로그 글을 추가할 때마다 sitemap을 직접 수정할 필요 없이, 자동으로 최신 상태를 유지하게 되었습니다.
- Next.js의 MetadataRoute.Sitemap를 사용하면 간편하게 동적 sitemap을 생성할 수 있고, robots.txt나 manifest.json도 동적으로 생성할 수 있습니다.
- Next.js로 블로그를 운영중인 분들은 이 방법을 적용하면 운영을 더 효율적으로 할 수 있을것 같습니다.