Next.js App Router Guide: JSON-LD (Structured Data)
무엇을 해결하나?
JSON-LD는 검색엔진(SEO)과 AI가 페이지의 “의미(구조화된 정보)”를 이해하도록 돕는 구조화 데이터 포맷입니다. 제품(Product), 사람(Person), 이벤트(Event) 등 다양한 엔티티를 설명할 수 있어요.
Next.js의 현재 권장 방식은 layout 또는 page에서 <script type="application/ld+json">로 렌더링하는 것입니다.
기본 구현 패턴 (App Router)
1) JSON-LD 객체 만들기
예시: Product 스키마
// app/products/[id]/page.tsx (예시)
export default async function Page({ params }) {
const { id } = await params
const product = await getProduct(id)
const jsonLd = {
'@context': 'https://schema.org',
'@type': 'Product',
name: product.name,
image: product.image,
description: product.description,
}
return (
<section>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify(jsonLd).replace(/</g, '\\u003c'),
}}
/>
{/* ... */}
</section>
)
}
보안 주의 (XSS)
가이드 예시는 JSON.stringify를 사용하며, 악의적인 문자열이 섞이면 XSS 가능성이 있을 수 있다고 경고합니다.
따라서 예시처럼 < 문자를 유니코드로 바꾸는 식으로(예: replace(/</g, '\u003c')) 잠재적으로 위험한 문자열을 정리(sanitize) 하는 방식을 고려해야 합니다.
- 팀/조직의 보안 가이드에 맞는 sanitize 방식을 적용
- 커뮤니티 대안(예:
serialize-javascript) 사용 고려
검증/테스트
- Google: Rich Results Test
- 일반: Schema Markup Validator
TypeScript 타입 지정(선택)
커뮤니티 패키지(schema-dts)로 JSON-LD 객체를 타입 안전하게 작성할 수 있습니다.
import { Product, WithContext } from 'schema-dts'
const jsonLd: WithContext<Product> = {
'@context': 'https://schema.org',
'@type': 'Product',
name: 'Next.js Sticker',
image: 'https://nextjs.org/imgs/sticker.png',
description: 'Dynamic at the speed of static.',
}