🎨Frontend

Next.js 14 sitemap-image 버그 탈출! 동적 모드 직접 구현 가이드 (2026)

Next.js 14 동적 모드에서 sitemap-image 버그를 겪으셨나요? MetadataRoute.Sitemap의 한계를 극복하고 sitemap.xml을 직접 구현하는 방법을 안내합니다.

📅 2026년 5월 17일·📖 7분 읽기·👁 31

Next.js 14 sitemap-image 버그 탈출! 동적 모드 직접 구현 가이드 (2026)

요즘 Next.js 14로 프로젝트를 진행하면서 sitemap-image 확장에 발목 잡혔던 경험을 공유하려고 해요. 동적 모드에서 MetadataRoute.Sitemap 기능을 썼는데, 아무리 images 필드를 채워도 sitemap-image가 제대로 작동하지 않더라고요.

시도와 함정

처음에는 Next.js 14의 MetadataRoute.Sitemap 기능을 그대로 사용하려고 했어요. src/app/sitemap.ts 파일에 images 필드를 추가하고 curl로 확인해보니, 분명히 images: [...]를 넣었는데도 <image:image> 태그가 하나도 안 잡히는 거예요.

// src/app/sitemap.ts (기존 시도)
import { MetadataRoute } from 'next';

export default function sitemap(): MetadataRoute.Sitemap { return [ { url: 'https://example.com/posts/1', lastModified: new Date('2026-05-17'), images: [ { url: 'https://example.com/images/post1.jpg', alt: 'Post 1 Image', width: 1200, height: 630, }, ], }, // ... other URLs ]; }

curl -I https://example.com/sitemap.xml 명령어로 확인했을 때, images 필드가 제대로 반영되지 않는 것을 보니 뭔가 Next.js 내부에서 동적 모드와 MetadataRoute.Sitemapimages 필드 간에 호환성 문제가 있는 것 같았어요. 3시간 정도 삽질 끝에 이 결론에 도달했죠.

원인

결론적으로, Next.js 14의 동적 모드에서 MetadataRoute.Sitemap 기능이 images 필드를 제대로 파싱해서 sitemap-image 확장에 반영하지 못하는 버그였습니다. Next.js 자체의 문제로 추정되는데, 직접 해결하기보다는 우회하는 방법을 찾아야 했어요.

해결

그래서 rss.xml/route.ts를 만들던 것처럼, sitemap XML을 직접 생성하는 방식으로 전환했습니다. src/app/sitemap.xml/route.ts 파일을 만들고 sitemap 프로토콜과 sitemap-image 확장을 직접 구현하는 거죠.

// src/app/sitemap.xml/route.ts
import { MetadataRoute } from 'next';

export async function GET() { const sitemapEntries: MetadataRoute.Sitemap = [ { url: 'https://example.com/posts/1', lastModified: new Date('2026-05-17'), changefreq: 'weekly', priority: 0.9, images: [ { url: 'https://example.com/images/post1.jpg', alt: 'Post 1 Image', width: 1200, height: 630, }, ], }, { url: 'https://example.com/about', lastModified: new Date('2026-05-17'), changefreq: 'monthly', priority: 0.7, }, ];

const xml = &lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt; &lt;urlset xmlns=&quot;http://www.sitemaps.org/schemas/sitemap/0.9&quot; xmlns:image=&quot;http://www.google.com/schemas/sitemap-image/1.1&quot;&gt; ${sitemapEntries.map(entry =&gt; <url> <loc>${entry.url}</loc> <lastmod>${entry.lastModified.toISOString().split('T')[0]}</lastmod> <changefreq>${entry.changefreq || 'daily'}</changefreq> <priority>${entry.priority || 0.5}</priority> ${entry.images?.map(image => &lt;image:image&gt; &lt;image:loc&gt;${image.url}&lt;/image:loc&gt; &lt;image:caption&gt;${image.alt || ''}&lt;/image:caption&gt; &lt;/image:image&gt;).join('') || ''} </url> ).join('')} &lt;/urlset&gt;;

return new Response(xml, { headers: { 'Content-Type': 'application/xml', }, }); }

이렇게 하면 xmlns:image 네임스페이스를 명시적으로 추가하고, 각 URL에 대한 <image:image> 태그와 <image:loc> 태그를 직접 제어할 수 있어요. lastmod, changefreq, priority 같은 속성들도 직접 설정해주니 훨씬 안정적이더라고요.

결과

  • sitemap-image 확장이 정상적으로 동작하여 검색 엔진이 이미지까지 인덱싱할 수 있게 되었습니다.
  • SEO 최적화가 강화되어 검색 결과에서의 노출 가능성이 높아졌습니다.
  • Next.js 버그에 대한 직접적인 의존성을 줄여 안정성을 확보했습니다.

정리 — 같은 함정 안 빠지려면

  • [ ] Next.js 내장 기능 사용 시, 특히 동적 모드에서는 예상치 못한 버그가 있을 수 있다는 점을 항상 염두에 두세요.
  • [ ] MetadataRoute 사용 시 images 필드 등 특정 기능이 제대로 동작하는지 curl 등으로 직접 검증하는 습관을 들이세요.
  • [ ] SEO 관련 기능은 직접 구현하는 것이 장기적으로 더 안정적이고 최적화에 유리할 수 있습니다.
  • [ ] sitemap.xml/route.ts 와 같이 직접 XML을 생성하는 방식은 유연성이 높으니 필요하면 고려해보세요.

태그

#Next.js#sitemap-image#동적 모드#MetadataRoute.Sitemap#XML 구현#버그 해결#프론트엔드

📨 박주니에게 한마디

스팸·악성 메시지 방지를 위해 구글 로그인 후 메시지를 보낼 수 있어요. 비공개로 전달되며, 운영자 외에는 볼 수 없습니다.

Google 로그인 후 메시지 남기기