정의
같은 메타데이터(제목·설명·날짜·태그 등 글에 관한 정보)를 검색엔진용·공유용 여러 산출물에 각각 적어두다 보면 값이 서로 어긋나기 마련인데, 이를 막고 싶을 때 쓰는 원칙이다. 핵심은 그 정보를 **딱 한 곳(단일 소스)**에만 두는 것.
원칙: 메타데이터를 하나의 권위 있는 출처(예: 콘텐츠 파일 상단의 frontmatter — 파일 맨 위 --- 사이에 적는 메타 정보 블록)에만 두고, 거기서 파생되는 산출물은 빌드할 때 그 출처로부터 자동 생성한다. 파생 산출물이란 sitemap(검색엔진에 페이지 목록을 알려주는 XML), RSS(구독용 글 목록 피드), OG(카카오·트위터 등에서 링크를 카드로 보여줄 때 쓰는 og:title·og:image 같은 메타 태그), JSON-LD(구글이 이해하는 구조화 데이터) 같은 것이다. 이렇게 하면 하나만 고쳐도 나머지가 항상 같은 값으로 다시 만들어진다("결정적"으로 생성 — 같은 입력이면 항상 같은 출력).
왜 필요한가
같은 메타를 여러 곳(런타임 DB, 별도 설정, 하드코딩)에 중복 저장하면 시간이 지나며 값이 어긋나는 drift가 생기고, 무엇이 진실인지 모호해진다. 단일 소스를 두면 일관성이 구조적으로 보장되고, 파생물은 재생성 가능한 결정적 함수의 결과가 된다. 정적 생성(SSG) 환경에서는 런타임 DB 없이도 빌드 시 콘텐츠를 스캔해 메타를 확정할 수 있다.
동작 원리
- 콘텐츠 파일의 frontmatter를 단일 출처로 삼고 스키마로 검증한다.
- 빌드 시
content/를 스캔 → 파서(gray-matter 등) → 스키마(Zod 등)로 정규화한다. - 정규화된 메타로 페이지 메타데이터·sitemap·robots·RSS·JSON-LD를 빌드타임 함수가 생성한다.
- AI 같은 보조 생성은 빈 description 등 빈칸 추천에만 쓰고, 확정 값은 소스에 적어 다시 결정적으로 흡수한다.
실무 적용
디렉터리 구조와 frontmatter를 일치시키는 불변식(예: 디렉터리 category === frontmatter category)을 두면 분류 drift도 빌드에서 차단할 수 있다.
트레이드오프
단일 소스는 일관성·재현성이 높지만, 동적으로 자주 바뀌는 메타(실시간 카운트 등)에는 빌드타임 결정이 맞지 않는다. 런타임 DB는 동적성에 강하지만 SSOT를 깨면 drift·비결정성을 떠안는다. 정적 콘텐츠 메타에는 SSOT가, 진짜 동적 데이터에는 런타임 소스가 적합하다.
사용하면 안 되는 경우
조회수·재고·실시간 가격처럼 본질적으로 런타임에 변하는 값은 빌드타임 단일 소스에 넣지 않는다. 이런 값은 별도 런타임 소스를 두고, 정적 메타와 분리한다.
흔한 실수
- 같은 메타를 frontmatter와 런타임 DB 양쪽에 두고 어느 쪽이 진실인지 합의하지 않음.
- AI 자동 생성값을 검수 없이 소스로 승격해 단일 소스를 오염.
- 스키마 검증을 빌드 파이프라인에 연결하지 않아 필수 필드 누락이 런타임까지 흘러감.
관련 개념
- serverless-stateless-execution — 런타임 상주 DB를 피하고 빌드 산출물로 결정하는 선택과 맞닿음.