← 전체 글로 돌아가기

Next.js

Next.js sitemap.xml에 새 글이 빠지는 이유와 확인 방법

Next.js에서 sitemap을 정적으로 생성하면 빌드 시점의 글만 포함된다. 글을 발행한 뒤 사이트맵이 갱신됐는지 직접 확인하는 것이 필요하다.

새 글을 올리고 Google Search Console에서 색인 요청을 했는데, sitemap에 해당 URL이 없다는 걸 나중에 발견한 적이 있다. 글은 사이트에서 잘 보이는데 sitemap에는 빠져 있는 상황이었다.

정적 sitemap과 동적 sitemap의 차이

Next.js에서 sitemap을 구성하는 방법은 크게 두 가지다.

정적 public/sitemap.xml: 파일을 직접 작성하거나 빌드 스크립트로 생성한다. 빌드 시점의 URL만 포함되므로, 새 글을 올릴 때마다 다시 빌드하거나 파일을 수동으로 업데이트해야 한다.

app/sitemap.ts (동적 생성): App Router에서 지원하는 방식으로, 요청마다 또는 ISR 주기로 sitemap을 생성한다.

// app/sitemap.ts
import { MetadataRoute } from 'next'

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await getAllPublishedPosts()  // DB에서 직접 조회

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
    },
    ...posts.map((post) => ({
      url: `https://example.com/posts/${post.slug}`,
      lastModified: post.updatedAt,
    })),
  ]
}

sitemap 확인 방법

배포 후 브라우저에서 /sitemap.xml에 접속하거나 curl로 직접 확인한다.

curl -s https://example.com/sitemap.xml | grep '<loc>'
# <loc>https://example.com/</loc>
# <loc>https://example.com/posts/첫번째-글</loc>
# ...

새로 올린 글의 URL이 목록에 있는지 확인한다. 없다면 아래 원인을 점검한다.

흔한 원인

정적 빌드 시 DB 접근 실패: 빌드 환경에서 데이터베이스에 연결할 수 없으면 글 목록을 가져오지 못하고 빈 sitemap이 생성된다. 빌드 로그에 에러가 찍히는지 확인한다.

next-sitemap 라이브러리 설정 누락: next-sitemap을 쓰는 경우 postbuild 스크립트에서 실행되므로, 빌드 후 이 스텝이 정상 완료됐는지 확인해야 한다.

// package.json
"scripts": {
  "build": "next build",
  "postbuild": "next-sitemap"  // 이 줄이 없으면 sitemap이 생성되지 않는다
}

캐시 문제: output: 'export' 정적 내보내기 방식이라면 빌드를 다시 해야 반영된다. Vercel이나 Cloudflare Pages라면 배포 후 CDN 캐시가 만료될 때까지 기다리거나 퍼지(purge)해야 한다.

Google Search Console 제출

URL이 sitemap에 포함됐다면 Search Console에서 sitemap URL을 제출하거나, URL 검사 도구로 색인 요청을 넣는다. 색인이 반영되는 데는 며칠이 걸릴 수 있다.