Next.js 15 메타태그 완벽 가이드 — og:image부터 hreflang까지
Next.js 15는 App Router 기반의 Metadata API를 통해 정적·동적 메타태그를 선언적으로 관리할 수 있다. generateMetadata() 함수로 페이지별 동적 og:image, title, description을 자동 생성할 수 있다.
광고
핵심 요약
>
- Next.js 15는 App Router 기반의 Metadata API를 통해 정적·동적 메타태그를 선언적으로 관리할 수 있다. -
generateMetadata()함수로 페이지별 동적 og:image, title, description을 자동 생성할 수 있다. - Twitter Card, hreflang, canonical URL, 구조화 데이터(JSON-LD)까지 단일 파일에서 제어 가능하다. - 잘못 설정된 메타태그는 소셜 미리보기 오류와 검색 순위 하락으로 직결되므로, 메타태그 검사 도구로 배포 전 반드시 점검하자.
Next.js 15 Metadata API란 무엇인가?
Next.js 13부터 도입된 App Router는 기존 컴포넌트 방식을 대체하는 Metadata API를 제공한다. Next.js 15에서는 이 API가 더욱 정교해져, layout.tsx와 page.tsx 파일에서 metadata 객체를 내보내거나 generateMetadata() 함수를 사용하는 두 가지 방식으로 메타태그를 제어할 수 있다.
정적 메타데이터
가장 간단한 형태는 metadata 객체를 직접 내보내는 방식이다.
// app/page.tsx
import type { Metadata } from 'next'
export const metadata: Metadata = {
title: 'Next.js 15 메타태그 가이드',
description: 'og:image부터 hreflang까지, Next.js 메타태그의 모든 것',
}
이 방식은 콘텐츠가 빌드 시점에 확정되는 정적 페이지에 적합하다. 블로그 홈이나 소개 페이지처럼 내용이 자주 바뀌지 않는 경우에 사용한다.
동적 메타데이터: generateMetadata()
블로그 포스트나 상품 상세 페이지처럼 URL 파라미터에 따라 내용이 달라지는 경우에는 generateMetadata() 함수를 사용한다.
// app/blog/[slug]/page.tsx
import type { Metadata, ResolvingMetadata } from 'next'
type Props = {
params: { slug: string }
}
export async function generateMetadata(
{ params }: Props,
parent: ResolvingMetadata
): Promise<Metadata> {
const post = await fetchPost(params.slug)
return {
title: post.title,
description: post.excerpt,
openGraph: {
title: post.title,
description: post.excerpt,
images: [{ url: post.ogImage, width: 1200, height: 630 }],
},
}
}
generateMetadata()는 서버에서 실행되므로 데이터베이스 조회나 외부 API 호출이 가능하다. 반환값은 Metadata 타입이며, Next.js가 자동으로 태그에 주입한다.
og:image를 제대로 설정하는 방법은 무엇인가?
Open Graph 이미지는 카카오톡, 슬랙, 트위터 등 소셜 플랫폼에서 링크를 공유할 때 나타나는 미리보기 이미지다. 잘못 설정하면 빈 이미지나 깨진 레이아웃이 노출되어 클릭률이 크게 떨어진다.
기본 og:image 설정
export const metadata: Metadata = {
openGraph: {
title: '페이지 제목',
description: '페이지 설명',
url: 'https://example.com/blog/my-post',
siteName: '사이트 이름',
images: [
{
url: 'https://example.com/og/my-post.png',
width: 1200,
height: 630,
alt: '게시글 대표 이미지',
},
],
locale: 'ko_KR',
type: 'article',
},
}
Next.js의 동적 og:image 생성 — ImageResponse
Next.js 15는 next/og의 ImageResponse를 활용해 서버에서 OG 이미지를 동적으로 렌더링하는 기능을 지원한다. 별도의 이미지 편집 없이 코드로 디자인을 제어할 수 있다.
// app/og/route.tsx
import { ImageResponse } from 'next/og'
export const runtime = 'edge'
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const title = searchParams.get('title') ?? '기본 제목'
return new ImageResponse(
(
<div
style={{
display: 'flex',
fontSize: 60,
background: '#0f172a',
color: 'white',
width: '100%',
height: '100%',
alignItems: 'center',
justifyContent: 'center',
padding: '40px',
}}
>
{title}
</div>
),
{ width: 1200, height: 630 }
)
}
이후 generateMetadata()에서 해당 엔드포인트를 참조하면 된다.
images: [{ url: `https://example.com/og?title=${encodeURIComponent(post.title)}` }]
Twitter Card 설정
Twitter(현 X)는 자체 메타태그 규격을 사용하지만, Next.js Metadata API는 이를 twitter 키로 통합 관리한다.
export const metadata: Metadata = {
twitter: {
card: 'summary_large_image',
title: '페이지 제목',
description: '페이지 설명',
creator: '@handle',
images: ['https://example.com/og/my-post.png'],
},
}
card 값은 summary, summary_large_image, app, player 중 선택한다. 블로그 포스트에는 summary_large_image가 가장 적합하다.
hreflang으로 다국어 SEO를 완성하는 방법
hreflang 태그는 동일한 콘텐츠의 언어·지역별 버전을 검색 엔진에 알려주는 신호다. 한국어와 영어 버전을 함께 운영하는 사이트라면 반드시 설정해야 한다. 설정이 누락되면 구글이 언어별 페이지를 중복 콘텐츠로 판단해 검색 노출에 불이익을 줄 수 있다.
alternates로 hreflang 설정
export const metadata: Metadata = {
alternates: {
canonical: 'https://example.com/ko/blog/my-post',
languages: {
'ko-KR': 'https://example.com/ko/blog/my-post',
'en-US': 'https://example.com/en/blog/my-post',
'ja-JP': 'https://example.com/ja/blog/my-post',
},
},
}
Next.js는 이 설정을 기반으로 아래와 같은 태그를 자동 생성한다.
<link rel="canonical" href="https://example.com/ko/blog/my-post" />
<link rel="alternate" hreflang="ko-KR" href="https://example.com/ko/blog/my-post" />
<link rel="alternate" hreflang="en-US" href="https://example.com/en/blog/my-post" />
<link rel="alternate" hreflang="ja-JP" href="https://example.com/ja/blog/my-post" />
canonical URL 설정의 중요성
canonical URL은 동일하거나 유사한 콘텐츠가 여러 URL에 존재할 때 검색 엔진에게 "이 URL이 원본"임을 알리는 태그다. 페이지네이션, UTM 파라미터, www 유무 차이 등으로 중복 URL이 발생하는 경우 canonical 설정이 없으면 검색 점수가 분산된다.
alternates: {
canonical: 'https://example.com/blog/my-post',
}
절대 경로를 사용하고, HTTPS와 www 여부를 사이트 전체에 걸쳐 일관되게 유지해야 한다.
구조화 데이터(JSON-LD)로 리치 결과 획득하기
구조화 데이터는 검색 결과에 별점, 작성자, 게시일 등의 추가 정보를 표시하는 리치 결과를 가능하게 한다. Next.js에서는 태그를 직접 삽입하는 방식을 권장한다.
// app/blog/[slug]/page.tsx
export default async function BlogPost({ params }: Props) {
const post = await fetchPost(params.slug)
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Article',
headline: post.title,
description: post.excerpt,
author: {
'@type': 'Person',
name: post.author,
},
datePublished: post.publishedAt,
dateModified: post.updatedAt,
image: post.ogImage,
}
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article>{/* 콘텐츠 */}</article>
</>
)
}
블로그 포스트에는 Article, 상품 페이지에는 Product, FAQ 페이지에는 FAQPage 스키마를 사용한다. Google의 리치 결과 테스트 도구로 유효성을 검증한 뒤 메타태그 검사 도구로 최종 확인하는 것을 권장한다.
메타태그 설정 시 자주 발생하는 실수
title 템플릿 활용
layout.tsx에서 title.template을 설정하면 하위 페이지의 title에 자동으로 사이트 이름이 붙는다.
// app/layout.tsx
export const metadata: Metadata = {
title: {
template: '%s | 사이트명',
default: '사이트명',
},
}
// app/blog/page.tsx
export const metadata: Metadata = {
title: '블로그', // 렌더링 결과: "블로그 | 사이트명"
}
메타데이터 병합 동작 이해
Next.js는 부모 레이아웃의 metadata와 자식 페이지의 metadata를 자동으로 병합한다. 단, 같은 키가 있을 경우 자식이 우선한다. openGraph 같은 객체 타입은 부분 병합이 아닌 전체 교체가 일어나므로, 자식 페이지에서 openGraph를 설정할 때는 필요한 필드를 모두 명시해야 한다.
FAQ
Q. Pages Router에서도 Metadata API를 사용할 수 있나요?
아니다. Metadata API는 App Router 전용이다. Pages Router에서는 기존 방식대로 next/head의 컴포넌트를 사용해야 한다. 두 라우터를 함께 사용하는 마이그레이션 과정에서는 각각 별도로 관리해야 한다.
Q. og:image의 권장 크기는 얼마인가요?
1200×630px이 표준이다. 최소 600×315px 이상이어야 하며, 파일 크기는 8MB 이하를 권장한다. 카카오톡은 200×200px 이상의 이미지를 요구하므로, 정사각형 버전을 별도로 준비하거나 비율에 맞게 크롭되도록 구성하는 것이 좋다.
Q. generateMetadata()에서 fetch 요청이 중복되지 않나요?
Next.js는 동일한 URL에 대한 fetch 요청을 자동으로 메모이제이션한다. generateMetadata()와 Page 컴포넌트에서 동일한 엔드포인트를 호출해도 실제 네트워크 요청은 한 번만 발생한다.
Q. hreflang 설정 후 효과가 나타나기까지 얼마나 걸리나요?
구글이 변경된 hreflang을 크롤링하고 반영하기까지 통상 2~4주가 소요된다. 사이트맵에도 hreflang 정보를 포함시키면 크롤링 속도를 높일 수 있다.
Q. Twitter Card와 og:image 이미지를 다르게 설정해야 하나요?
필수는 아니다. twitter.images를 별도로 지정하지 않으면 Twitter는 og:image를 폴백으로 사용한다. 다만 Twitter의 summary_large_image 카드는 2:1 비율을 사용하고, 일부 플랫폼은 1:1 비율을 선호하므로 플랫폼별 최적화가 필요하다면 각각 지정하는 것이 낫다.
Q. 메타태그 설정이 올바른지 어떻게 확인하나요?
메타태그 검사 도구를 활용하면 URL 하나로 og:image, twitter card, canonical, hreflang 등 주요 메타태그를 한 번에 점검할 수 있다. 배포 전 스테이징 환경에서 소셜 플랫폼의 공식 디버거(Facebook Sharing Debugger, Twitter Card Validator)와 함께 사용하면 더욱 정확하다.
정리: Next.js 15 메타태그 설정 체크리스트
Next.js 15 Metadata API는 SEO에 필요한 거의 모든 메타태그를 타입 안전하게 관리할 수 있는 강력한 도구다. 프로젝트에 적용할 때 아래 항목을 순서대로 확인하자.
- title 템플릿 —
layout.tsx에title.template설정 - description — 페이지별로 120~160자의 고유한 설명 작성
- og:image — 1200×630px, 절대 경로 URL로 지정
- Twitter Card —
card: 'summary_large_image'설정 - canonical URL —
alternates.canonical에 절대 경로 명시 - hreflang — 다국어 운영 시
alternates.languages설정 - 구조화 데이터 — 페이지 유형에 맞는 JSON-LD 스키마 삽입
- 최종 검증 — 메타태그 검사 도구로 배포 전 점검
메타태그는 작성하는 데 시간이 오래 걸리지 않지만, 누락되거나 잘못 설정된 경우 소셜 공유 경험과 검색 노출 모두에 장기간 부정적인 영향을 미친다. 초기 설정에 공을 들이고, 주요 페이지가 추가될 때마다 체크리스트를 반복하는 습관을 들이면 SEO 기반을 탄탄하게 유지할 수 있다.
광고
🔧 이 글과 관련된 무료 도구
이 글과 관련된 상품 (Next.js)[광고/제휴]
이 포스팅은 쿠팡 파트너스, 아마존 어소시에이트, 알리익스프레스 제휴 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다. 이는 상품 가격에 영향을 주지 않습니다.
As an Amazon Associate, Coupang Partner, and AliExpress affiliate, I earn from qualifying purchases at no extra cost to you.
관련 글
DNS(Domain Name System)는 도메인 주소를 IP 주소로 변환해주는 인터넷의 '전화번호부'다. 레코드 종류마다 역할이 다르다. A...
IT·개발Core Web Vitals 개선 실전 — LCP 3초→1.2초 줄인 방법LCP(Largest Contentful Paint)는 Google 검색 순위에 직접 영향을 주는 핵심 지표다. 이미지 최적화, 폰트 로딩 전략...
IT·개발2026 최고의 무료 온라인 도구 18선 — 계산기·변환기·분석기유료 소프트웨어 없이도 할 수 있는 일이 훨씬 많아졌습니다. 계산기·단위 변환기·이미지 최적화·SEO 분석기·개발자 도구 등 실무에서 바로 쓸 ...
광고