
Sitemap(사이트맵)이란 웹사이트의 구조를 한눈에 보여주는 지도 같은 것입니다. 웹사이트 안에 어떤 페이지들이 있고, 그 페이지들이 어떻게 연결되어 있는지를 정리해 놓은 목록으로 검색 엔진(예: 구글, 네이버)을 위한 웹사이트의 지도입니다. 사이트의 페이지들을 자동으로 수집(크롤링)할 수 있게 도와주기 때문에 sitemap은 검색 엔진 최적화에 중요한 역할을 합니다.
Next.js v14 App Router 기준으로 sitemap.xml 생성 방법에 대해 설명합니다.
간단한 사이트 같은 경우 app 폴더에서 sitemap.xml 파일을 만들어 정적 사이트맵을 생성할 수 있습니다.
예를 들어 main 페이지와 about 페이지가 존재한다고 하였을 때 아래와 같은 사이트 맵을 생성할 수 있습니다.
// /app/sitemap.xml
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://mysite.com</loc>
<lastmod>2024-04-05T16:47:38.737Z</lastmod>
<changefreq>daily</changefreq>
<priority>1</priority>
</url>
<url>
<loc>https://mysite.com/about</loc>
<lastmod>2024-04-05T16:47:38.737Z</lastmod>
<changefreq>daily</changefreq>
<priority>0.8</priority>
</url>
</urlset>
💡 sitemap 태그 설명
| 태그 이름 | 필수 여부 | 설명 | 예시 값 | 비고 |
|---|---|---|---|---|
<urlset> | ✅ 필수 | 전체 sitemap을 감싸는 루트 요소. XML 네임스페이스 포함해야 함 | <urlset xmlns="..."> | 하나의 sitemap에 한 번만 등장 |
<url> | ✅ 필수 | 개별 URL 정보를 감싸는 요소 | <url> ... </url> | 여러 개 포함 가능 |
<loc> | ✅ 필수 | 실제 페이지의 절대 경로(전체 URL) | https://mysite.com/page1 | 반드시 전체 URL 사용 |
<lastmod> | ⭕ 선택 | 해당 페이지가 마지막으로 수정된 날짜 | 2025-04-24T10:20:00+00:00 | ISO 8601 형식 권장 |
<changefreq> | ⭕ 선택 | 페이지가 얼마나 자주 변경되는지를 나타냄 | always, daily, monthly | 검색 엔진 참고용 |
<priority> | ⭕ 선택 | 해당 URL의 상대적 중요도 (0.0 ~ 1.0) | 0.8 | 기본값은 0.5, SEO에 큰 영향 없음 |
생성할 정적 사이트맵의 수가 많은 경우 next-sitemap 라이브러리를 사용하여 빌드 시 자동으로 사이트맵이 생성되도록 할 수 있습니다.
next-sitemap 라이브러리를 사용하여 빌드 시 자동으로 사이트맵을 생성할 수 있습니다.
먼저, next-sitemap 라이브러리를 설치합니다.
npm i -D next-sitemap
package.json 파일 scripts에 명령어를 추가합니다.
//...
"scripts": {
//...
"postbuild": "next-sitemap"
}
//...
root 폴더에 next-sitemap.config.js 파일을 생성합니다.
module.exports = {
siteUrl: "https://mysite.com",
generateRobotsTxt: true,
sitemapSize: 5000,
changefreq: "weekly",
priority: 0.7,
exclude: [], // 제외할 경로
이후 빌드 시 자동으로 public 폴더에 sitemap.xml 파일이 생성됩니다.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://mysite.com</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/about</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
</urlset>
next-sitemap 라이브러리는 빌드 시 동적 사이트 맵을 생성하는 기능이 존재합니다.
이 기능은 next-sitemap.config.js 파일에 additionalPaths 옵션을 추가하여 설정할 수 있습니다.
아래는 포스트 동적 sitemap 생성을 추가하는 예시입니다.
const { getPostsId } = require('./lib/api');
module.exports = {
siteUrl: "https://mysite.com",
generateRobotsTxt: true,
sitemapSize: 5000,
changefreq: "weekly",
priority: 0.7,
exclude: [], // 제외할 경로
additionalPaths: async () => {
// 동적으로 sitemap 생성
// 모든 포스터 아이디를 가져오는 API
const postsId = await getPostsId();
const postPaths = postsId.map((id) => ({
loc: `/post/${id.toString()}`,
lastmod: new Date().toISOString()
}));
return postPaths;
}
이후 빌드 시 자동으로 public 폴더에 sitemap.xml 파일이 생성됩니다.
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://mysite.com</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/about</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/post/2</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/post/1</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
</urlset>
Next.js에서는 app/sitemap.xml/route.ts를 이용하여 요청이 들어올 때마다 동적으로 sitemap을 생성할 수 있습니다.
app/sitemap.xml/route.ts 폴더 및 파일을 생성합니다.
// /app/sitemap.xml/route.ts
import { NextResponse } from 'next/server';
import { getPostsId } from '@/lib/api';
export default async function GET() {
// 정적 URLs
const staticURLs = [
{
loc:"https://mysite.com",
lastmod:new Date().toISOString()
},
{
loc:"https://mysite.com/about",
lastmod:new Date().toISOString()
}
];
// 모든 포스트 아이디를 가져오는 API
const postsId = await getPostsId();
// 동적 postsURLs
const postsURLs = postsId.map((p) => ({
loc: `${BASE_URL}/product/${p._id.toString()}`,
lastmod: new Date().toISOString()
}));
// 정적 urls, 동적 urls를 병합하여 sitemap 생성
const urls = [...staticURLs, ...postsURLs]
.map((data) => {
return `
<url>
<loc>${data.loc}</loc>
<lastmod>${data.lastmod}</lastmod>
</url>
`;
})
.join("");
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls}
</urlset>`;
return new NextResponse(xml, {
headers: {
"Content-Type": "application/xml"
}
});
}
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://mysite.com</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/about</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/post/2</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
<url>
<loc>https://mysite.com/post/1</loc>
<lastmod>2025-04-24T09:32:12.000Z</lastmod>
</url>
</urlset>