← 전체 글로 돌아가기

Next.js

Next.js App Router에서 sitemap.xml과 robots.txt 직접 구현하기

next-sitemap 없이 App Router의 파일 컨벤션만으로 sitemap.xml과 robots.txt를 구현하는 방법을 정리했다.

Next.js에서 sitemap.xml과 robots.txt를 따로 패키지 없이 직접 만들었다. App Router에서는 파일 기반으로 처리하는 방법이 있는데, 처음에는 찾는 데 시간이 좀 걸렸다.

왜 직접 만들었나

next-sitemap 같은 패키지를 쓰는 게 흔한 방법이지만, 글 목록을 DB에서 동적으로 가져오는 구조라 어차피 빌드 타임에 처리하기가 애매했다. App Router의 파일 컨벤션으로 직접 구현하는 게 더 깔끔했다.

sitemap.xml

app/sitemap.ts 파일을 만들면 /sitemap.xml 경로가 자동으로 생긴다. DB 조회도 그냥 넣으면 된다.

// app/sitemap.ts
import { MetadataRoute } from 'next';
import { db } from '@/lib/db';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const posts = await db.post.findMany({
    where: { published: true },
    select: { slug: true, updatedAt: true },
  });

  const postEntries = posts.map((post) => ({
    url: `https://example.com/posts/${post.slug}`,
    lastModified: post.updatedAt,
    changeFrequency: 'weekly' as const,
    priority: 0.8,
  }));

  return [
    {
      url: 'https://example.com',
      lastModified: new Date(),
      changeFrequency: 'daily',
      priority: 1,
    },
    ...postEntries,
  ];
}

반환값 타입을 MetadataRoute.Sitemap으로 맞춰야 빌드 오류 없이 넘어간다.

robots.txt

마찬가지로 app/robots.ts 파일 하나로 끝난다.

// app/robots.ts
import { MetadataRoute } from 'next';

export default function robots(): MetadataRoute.Robots {
  return {
    rules: {
      userAgent: '*',
      allow: '/',
      disallow: '/api/',
    },
    sitemap: 'https://example.com/sitemap.xml',
  };
}

확인 방법

로컬에서 npm run dev 실행 후 http://localhost:3000/sitemap.xmlhttp://localhost:3000/robots.txt로 직접 접속해보면 된다.

배포 후에는 구글 서치 콘솔과 네이버 서치어드바이저에서 각각 sitemap URL을 등록해두면 된다. 크롤러가 robots.txt를 먼저 확인하고 sitemap을 따라가는 구조이므로, 두 파일의 URL이 일치하는지 꼭 확인한다.