정적 메타데이터 설정
layout과 page의 metadata 객체로 제목·설명·canonical·아이콘을 선언해 검색 엔진에 페이지 정보를 전달합니다.
검색 엔진 최적화(SEO)는 웹사이트가 검색 결과에서 더 잘 노출되도록 만드는 필수 과정입니다.
SEO의 핵심 요소 중 하나가 메타데이터(Metadata) 설정입니다.
메타데이터는 페이지 내용을 검색 엔진과 소셜 플랫폼에 설명해, 페이지가 어떻게 인덱싱되고 노출될지 결정하는 데 큰 영향을 줍니다.
Next.js 13부터 도입된 App Router는 라우트별로 정적 메타데이터(Static Metadata)를 선언하는 API를 제공합니다.
이 절에서는 정적 메타데이터의 역할, App Router에서 설정하는 방법, SEO에 영향을 주는 주요 메타데이터 속성을 다룹니다.
App Router는 layout과 page에 선언한 metadata를 읽어 검색 엔진, 브라우저 탭, 공유 미리보기가 사용할 표준 신호로 정리한다.
- 1. 라우트에 선언
라우트에 선언 layout.tsx 또는 page.tsx에서 해당 범위의 metadata 객체를 export한다.
- 2. segment 순서로 해석
segment 순서로 해석 가까운 값이 우선한다. openGraph 같은 nested 필드는 부분 deep merge 없이 객체 단위로 교체된다.
- 3. 외부 표면에 노출
외부 표면에 노출 검색 결과, 브라우저 탭, SNS 카드가 같은 페이지 메시지를 사용한다.
메타데이터란 무엇이며 왜 중요한가요?
사용자는 본문을 보지만 검색 엔진, 브라우저, 공유 플랫폼은 metadata 값을 먼저 읽고 페이지의 의미를 판단한다.
- 메타데이터의 역할 메타데이터
페이지와 외부 시스템 사이의 설명서다
- 사용자 인지 검색 엔진 제목, 설명, robots 값
검색 결과 노출 후보를 만든다.
메타데이터는 "데이터에 대한 데이터"를 의미하며, 웹 페이지의 맥락에서는 해당 페이지의 콘텐츠를 설명하는 정보입니다.
HTML <head> 태그 내에 <meta> 태그, <title> 태그 등을 통해 정의됩니다.
- 검색 엔진 최적화 (SEO): 검색 엔진 크롤러는 메타데이터를 읽어 페이지의 주제와 관련성을 파악하고 검색 결과에 반영합니다. 정확하고 풍부한 메타데이터는 검색 엔진 순위를 높이는 데 기여합니다.
- 소셜 미디어 공유: Open Graph (OG) 및 Twitter Card 메타데이터는 웹 페이지가 Facebook, Twitter, LinkedIn 등 소셜 미디어 플랫폼에 공유될 때 미리보기(제목, 설명, 이미지)가 어떻게 표시될지 정의합니다. 이는 링크 클릭률을 높이는 데 중요한 역할을 합니다.
- 사용자 경험 개선: 브라우저 탭의 제목, 북마크 이름 등은 메타데이터를 통해 결정됩니다. 명확한 제목과 설명은 사용자에게 페이지의 내용을 미리 알려주는 역할을 합니다.
App Router에서 정적 메타데이터 설정하기
Next.js App Router에서 정적 메타데이터를 설정하는 가장 일반적이고 권장되는 방법은 metadata 객체를 layout.tsx 또는 page.tsx 파일에서 export하는 것입니다.
Next.js는 빌드 시점에 이 metadata 객체를 읽어 HTML <head> 태그에 필요한 메타 태그들을 자동으로 생성합니다.
기본 메타데이터 설정
애플리케이션 전체에 적용될 기본 메타데이터는 루트 layout.tsx 파일에서 설정합니다.
import type { Metadata, Viewport } from 'next';
import { Inter } from 'next/font/google';
import './globals.css';
const inter = Inter({ subsets: ['latin'] });
// 1. Metadata 객체 export
export const metadata: Metadata = {
title: 'Next.js 튜토리얼 - 성능 최적화와 SEO', // 웹사이트의 기본 제목
description: 'Next.js App Router를 사용하여 성능 최적화 및 SEO 설정을 학습하는 튜토리얼입니다.', // 웹사이트의 기본 설명
keywords: ['Next.js', 'React', '성능 최적화', 'SEO', '웹 개발'], // 관련 키워드
authors: [{ name: 'Your Name', url: 'https://personal-lab.dev' }], // 개발자 정보
creator: 'Your Name', // 제작자 정보
publisher: 'Your Company', // 발행자 정보
// Open Graph (소셜 미디어 공유 최적화)
openGraph: {
title: 'Next.js 튜토리얼 - 성능 최적화와 SEO',
description: 'Next.js App Router를 사용하여 성능 최적화 및 SEO 설정을 학습하는 튜토리얼입니다.',
url: 'https://personal-lab.dev', // 웹사이트의 표준 URL
siteName: 'Next.js 학습 사이트', // 웹사이트 이름
images: [
{
url: 'https://personal-lab.dev/og-image.png', // 소셜 미디어 공유 시 표시될 이미지
width: 1200,
height: 630,
alt: 'Next.js 튜토리얼 이미지',
},
],
locale: 'ko_KR', // 언어 및 지역 (예: 한국어)
type: 'website', // 페이지 타입 (website, article 등)
},
// Twitter Card (트위터 공유 최적화)
twitter: {
card: 'summary_large_image', // 카드 타입 (summary, summary_large_image, app, player)
title: 'Next.js 튜토리얼 - 성능 최적화와 SEO',
description: 'Next.js App Router를 사용하여 성능 최적화 및 SEO 설정을 학습하는 튜토리얼입니다.',
creator: '@yourtwitterhandle', // 트위터 계정
images: ['https://personal-lab.dev/twitter-image.png'], // 트위터 공유 시 표시될 이미지
},
// robots.txt 설정과 유사한 역할 (페이지 인덱싱 및 팔로우 제어)
robots: {
index: true, // 이 페이지를 인덱싱할지 여부
follow: true, // 이 페이지의 링크를 따라갈지 여부
nocache: true, // 캐시를 사용하지 않을지 여부
googleBot: { // GoogleBot 전용 설정
index: true,
follow: false,
noimageindex: true, // 이미지 인덱싱 방지
'max-video-preview': -1,
'max-snippet': -1,
},
},
};
// viewport와 themeColor는 Metadata가 아니라 Viewport API로 선언합니다.
export const viewport: Viewport = {
width: 'device-width',
initialScale: 1,
themeColor: '#FFFFFF',
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko">
<body className={inter.className}>{children}</body>
</html>
);
}페이지별 메타데이터 설정
특정 페이지에만 적용되는 메타데이터는 해당 페이지의 page.tsx 파일에서 metadata 객체를 export하여 설정합니다.
import type { Metadata } from 'next';
// 1. Dashboard 페이지의 metadata 객체 export
export const metadata: Metadata = {
title: '대시보드 - 내 계정 요약', // 이 페이지의 고유 제목 (루트 레이아웃의 제목을 덮어씀)
description: '사용자 계정의 대시보드입니다. 최신 활동, 알림 및 설정에 접근하세요.', // 이 페이지의 고유 설명
// Open Graph 등 다른 속성도 여기에 추가하거나 덮어쓸 수 있습니다.
openGraph: {
title: '대시보드 - Next.js 학습',
description: '나만의 Next.js 대시보드 페이지입니다.',
images: ['https://personal-lab.dev/dashboard-og.png'],
},
// robots: { index: false, follow: false }, // 특정 페이지를 검색에서 제외하고 싶을 때
};
export default function DashboardPage() {
return (
<div>
<h1>대시보드</h1>
<p>환영합니다! 이곳은 대시보드 페이지입니다.</p>
</div>
);
}Next.js는 루트 레이아웃에서 페이지로 내려오며 메타데이터를 해석하지만, 모든 필드를 깊게 병합하지는 않습니다.
title,description같은 단순 필드는 가까운 하위 세그먼트의 값이 상위 값을 덮어씁니다.openGraph,robots같은 중첩 필드도 하위 객체가 상위 객체를 얕게 교체합니다. 하위openGraph에description만 쓰면 상위openGraph.images가 자동으로 보존되지 않습니다.- 상위 배열이나 중첩 값을 함께 쓰려면 공통 변수를 임포트하거나
generateMetadata에서parent를 읽어 명시적으로 합칩니다.
아래 다이어그램은 route segment별 정적 메타데이터 병합 흐름과 속성별 점검 기준을 함께 정리한 것입니다.
metadata는 단순 deep merge가 아니다. 가까운 segment가 openGraph 같은 nested 필드를 선언하면 그 객체가 이전 값을 대신한다.
- 상위 layout openGraph
{ title: "Site", images: ["/base.png"] }
- 가까운 page openGraph
{ title: "Article" }
- 최종값 title
"Article" images는 이어지지 않음
- 공유 객체 const sharedOg = images
["/base.png"] }
- page에서 합성 openGraph
{ ...sharedOg, title: "Article" }
- 최종값 title
images를 모두 유지 공유 의도가 코드에 드러난다.
주요 메타데이터 속성 상세 설명
Metadata 타입은 다양한 SEO 및 소셜 미디어 관련 속성을 제공합니다.
-
title<title>태그에 해당하는 값입니다. 브라우저 탭에 표시되며, 검색 엔진 결과의 제목으로 사용됩니다.- 페이지의 내용을 간결하고 명확하게 요약해야 합니다.
- 권장 형식:
페이지 제목 | 웹사이트 이름또는웹사이트 이름 - 페이지 제목
-
description<meta name="description" content="..." />태그에 해당합니다. 검색 엔진 결과의 스니펫(요약)으로 사용될 수 있습니다.- 페이지의 내용을 1~2문장으로 요약하며, 관련 키워드를 포함하는 것이 좋습니다.
-
keywords<meta name="keywords" content="..." />태그에 해당합니다. 과거에는 중요했지만 현재 검색 엔진에서는 중요도가 낮아졌습니다. 그래도 관련 키워드를 포함하는 것이 좋습니다.
-
authors,creator,publisher- 콘텐츠의 저자, 제작자, 발행자 정보를 제공합니다.
-
openGraph(OG)- Facebook, LinkedIn 등 Open Graph 프로토콜을 사용하는 소셜 미디어 플랫폼에 페이지가 공유될 때 표시될 정보를 정의합니다.
title,description,url,siteName,images,locale,type등의 속성이 있습니다.images는 배열로 여러 이미지를 지정할 수 있습니다.
-
twitter- Twitter Card를 정의하여 트위터에 페이지가 공유될 때 표시될 정보를 제어합니다.
card타입 (summary,summary_large_image등),title,description,creator,images등의 속성이 있습니다.
-
robots<meta name="robots" content="..." />태그에 해당하며, 검색 엔진 크롤러에게 페이지를 어떻게 처리할지 지시합니다.index: true/false,follow: true/false등이 주요 속성입니다.index: false는 해당 페이지를 검색 결과에서 제외하라는 의미입니다.
-
ViewportAPIviewport객체 또는generateViewport함수로 화면 배율과themeColor를 선언합니다. 이 값들은Metadata객체에 넣지 않습니다.
-
icons- 파비콘(favicon) 및 기타 웹 아이콘을 설정합니다.
src/app/layout.tsx import type { Metadata } from 'next'; export const metadata: Metadata = { icons: { icon: '/logo.png', // 기본 파비콘 대체 경로 shortcut: '/logo.png', apple: '/logo.png', // iOS 홈 화면 아이콘 other: { rel: 'apple-touch-icon-precomposed', url: '/logo.png', }, }, };
아래 보드는 페이지별 정적 메타데이터를 작성할 때 SEO, 공유 미리보기, 인덱싱 설정을 어떤 순서로 점검할지 정리한 것입니다.
title과 description만 채우면 충분하지 않다. 실제 노출 표면별로 어떤 값이 쓰이는지 배포 전에 나누어 확인해야 한다.
- 정적 메타데이터 점검 보드 정적 메타데이터
검색, 공유, 모바일 표시를 함께 검증한다
- title
description만 채우면 충분하지 않다.
- 실제 노출 표면별
어떤 값이 쓰이는지 배포 전에 나누어 확인해야 한다.
- 검색 노출 title 페이지 고유 주제
사이트 이름이 구분되는지 본다.
정적 메타데이터 설정 시 고려사항
- 일관성 유지: 웹사이트 전체에서 메타데이터의 형식과 내용에 일관성을 유지하는 것이 중요합니다.
- 중복 피하기: 각 페이지마다 고유하고 관련성 높은 제목과 설명을 제공하여 중복된 콘텐츠로 인한 SEO 문제를 피합니다.
- 키워드 스터핑 지양:
keywords나description에 과도하게 키워드를 나열하는 것은 검색 엔진에 부정적인 영향을 줄 수 있습니다. 자연스러운 문장으로 작성하세요. - 이미지 경로 확인: 최종
og:image와 Twitter 이미지 URL은 절대 URL이어야 합니다. Metadata API에서는 루트에metadataBase를 지정하면/og-image.png같은 상대 경로를 사용할 수 있으며 Next.js가 절대 URL로 해석합니다. 어떤 방식을 쓰든 실제 공개 주소에서 이미지가 열리는지 확인합니다. - 정확성: 웹 페이지의 실제 내용을 정확하게 반영하는 메타데이터를 작성해야 합니다.
- 모바일 친화적:
viewport설정을 통해 모바일 기기에서의 표시를 최적화해야 합니다. - 테스트: 페이지를 배포한 후 Google Search Console, Open Graph Debugger (Facebook), Twitter Card Validator 등의 도구를 사용하여 메타데이터가 올바르게 인식되는지 확인합니다.
아래 다이어그램은 정적 메타데이터를 릴리스 전에 검색, 공유, 접근 제어 관점에서 점검하는 흐름을 정리한 것입니다.
코드에 객체를 작성한 뒤에는 검색 스니펫, 공유 카드, robots 의도가 실제 head 출력과 맞는지 확인해야 한다.
- 기본값 분리
공통 브랜드 정보는 layout에, 페이지 고유 메시지는 page에 둔다.
- 검색 문장 확인
title과 description이 본문 주제와 중복 없이 연결되는지 본다.
- 공유 이미지 검증
Open Graph 이미지가 절대 URL이고 접근 가능한지 확인한다.
- 색인 정책 확정
공개 페이지와 숨겨야 할 페이지의 robots 값을 분리한다.
아래 다이어그램은 App Router의 정적 메타데이터가 layout과 page 경계에서 상속, 재정의, 검색 노출로 이어지는 구조를 정리합니다.
공통 scalar 값은 상위 segment에 두되, openGraph 같은 nested 객체는 가까운 segment에서 완전한 값으로 다시 만들거나 공유 객체를 명시적으로 합성한다.
- layout에 두는 값브랜드
사이트 이름, 제목 템플릿, 기본 설명처럼 섹션 전체가 공유한다.
- page에서 구체화title
구체화하고, nested 필드는 부분 상속을 기대하지 않고 필요한 값을 모두 구성한다.
- 검색 결과
title과 description이 클릭 전 기대를 만든다.
- 브라우저 탭
title 템플릿이 현재 위치를 짧게 보여준다.
- 공유 카드
OG 값이 검색 문장과 같은 대상을 설명한다.
아래 다이어그램은 App Router의 metadata 객체가 title, description, openGraph 값을 계층적으로 합치는 방식을 보여줍니다.
각 metadata 필드는 다른 노출 표면을 담당한다. nested 객체는 가까운 segment가 교체하므로 필요한 하위 값을 완전하게 선언한다.
- 검색title · description
검색 결과와 브라우저 탭에서 페이지 목적을 짧게 설명한다.
- 공유openGraph · twitter
각 nested 객체를 독립된 완전한 카드 계약으로 구성한다.
- 크롤러robots
색인과 링크 추적 허용 범위를 명시한다.
- URLalternates · metadataBase
대표 주소와 상대 URL 해석 기준을 정한다.
Next.js App Router의 정적 메타데이터 기능을 사용하면 페이지별 제목, 설명, 공유 정보를 코드 가까이에 선언할 수 있습니다.
검색 노출과 소셜 공유 미리보기는 이 메타데이터의 일관성에 영향을 받습니다.
공통 기준과 page 고유값을 나누되, nested metadata는 자동 deep merge되지 않는다는 전제로 구성하고 실제 노출 표면을 확인한다.
- 기본값 정의
root layout에 사이트명, 제목 템플릿, metadataBase를 두고 재사용할 nested 값은 별도 객체로 만든다.
- 페이지 override
각 page는 title과 description을 구체화하고 필요한 nested 객체를 완전하게 선언한다.
- 공유 미리보기
공유값은 명시적으로 합성하고 openGraph와 twitter를 각각 검증한다.
- 중복 방지
canonical과 alternates로 대표 URL과 언어 변형을 정리한다.
- URL과 이미지 기준
metadataBase가 배포 도메인을 가리켜야 canonical과 공유 이미지가 절대 주소로 안정적으로 해석된다.
아래 다이어그램은 정적 메타데이터 설정을 검색 노출, 공유 미리보기, 크롤러 신호 기준으로 점검합니다.