stack-analysis
CHAPTER 18 / 90
읽기 약 2분
FUNCTION
SEO 완전 정복: 메타데이터 API + JSON-LD + sitemap
핵심 개념
generateMetadata·OG·Twitter Cards·sitemap.ts·robots.ts — 검색 1페이지.
본문
generateMetadata (동적)
// app/posts/[slug]/page.tsx
import type { Metadata } from 'next';
export async function generateMetadata({
params,
}: {
params: { slug: string };
}): Promise<Metadata> {
const post = await getPost(params.slug);
return {
title: post.title,
description: post.excerpt,
keywords: post.tags,
authors: [{ name: post.author.name }],
openGraph: {
title: post.title,
description: post.excerpt,
type: 'article',
publishedTime: post.publishedAt,
authors: [post.author.name],
images: [
{
url: post.coverImage,
width: 1200,
height: 630,
alt: post.title,
},
],
},
twitter: {
card: 'summary_large_image',
title: post.title,
description: post.excerpt,
images: [post.coverImage],
},
alternates: {
canonical: `https://example.com/posts/${params.slug}`,
languages: {
'en-US': `/en/posts/${params.slug}`,
'ja-JP': `/ja/posts/${params.slug}`,
},
},
};
}title.template (전역)
// app/layout.tsx
export const metadata: Metadata = {
metadataBase: new URL('https://example.com'),
title: {
template: '%s | My Site',
default: 'My Site — Home',
},
description: '기본 설명',
};
// 페이지에선 title: 'Post Title'만 작성
// → "Post Title | My Site" 자동 렌더JSON-LD (구조화 데이터)
// app/posts/[slug]/page.tsx
export default async function Page({ params }: { params: { slug: string } }) {
const post = await getPost(params.slug);
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'BlogPosting',
headline: post.title,
description: post.excerpt,
author: {
'@type': 'Person',
name: post.author.name,
url: `https://example.com/authors/${post.author.slug}`,
},
datePublished: post.publishedAt,
dateModified: post.updatedAt,
image: post.coverImage,
publisher: {
'@type': 'Organization',
name: 'My Site',
logo: { '@type': 'ImageObject', url: 'https://example.com/logo.png' },
},
};
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<article>{post.content}</article>
</>
);
}sitemap.ts
// app/sitemap.ts
import type { MetadataRoute } from 'next';
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const posts = await getAllPosts();
return [
{
url: 'https://example.com',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 1.0,
},
{
url: 'https://example.com/blog',
lastModified: new Date(),
changeFrequency: 'daily',
priority: 0.9,
},
...posts.map(post => ({
url: `https://example.com/posts/${post.slug}`,
lastModified: post.updatedAt,
changeFrequency: 'weekly' as const,
priority: 0.7,
})),
];
}robots.ts
// app/robots.ts
import type { MetadataRoute } from 'next';
export default function robots(): MetadataRoute.Robots {
return {
rules: [
{ userAgent: '*', allow: '/', disallow: ['/api/', '/admin/', '/private/'] },
{ userAgent: 'GPTBot', disallow: '/' }, // AI 크롤러 차단
],
sitemap: 'https://example.com/sitemap.xml',
};
}다음 챕터
CH.19 "성능 최적화" — 번들 분석 + Suspense.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 Next.js SEO 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
Next.js SEO 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 Next.js SEO 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 프론트엔드 시장의 Next.js SEO 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
SEO 완전 정복: 메타데이터 API + JSON-LD + sitemap는 이 3가지만 확실히 잡으세요
1.generateMetadata로 동적 OG/Twitter Card — 공유 시 미리보기
2.JSON-LD = Google 리치 결과 — 별점·작성자·날짜 노출
3.sitemap.ts + robots.ts로 인덱싱 제어 — 검색 색인 핵심
공유하기
진행도 18 / 90