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.xml과 http://localhost:3000/robots.txt로 직접 접속해보면 된다.
배포 후에는 구글 서치 콘솔과 네이버 서치어드바이저에서 각각 sitemap URL을 등록해두면 된다. 크롤러가 robots.txt를 먼저 확인하고 sitemap을 따라가는 구조이므로, 두 파일의 URL이 일치하는지 꼭 확인한다.