
Contentful은 API 우선 헤드리스 CMS로, 콘텐츠를 중앙 허브에 저장하고 REST 및 GraphQL API를 통해 모든 프론트엔드(웹, 모바일, IoT, 디지털 사이니지 등)에 전달합니다. 이 가이드는 경쟁사들이 생략하는 모든 것을 다룹니다: 실제 코드 예시, 실제 가격 정보, 그리고 솔직한 한계점들입니다.
우리는 Contentful의 직접적인 경쟁사인 Sanity를 4개의 웹사이트와 10개 언어로 프로덕션에 사용 중이므로, 벤더 피칭이 아닌 실무자 관점에서 이 글을 작성합니다.
빠른 요약
Contentful이란?
Contentful은 클라우드 네이티브 API 우선 헤드리스 CMS입니다. 최근에는 회사에서 이를 "조합 가능한 콘텐츠 플랫폼"이라고 부르고 있습니다. WordPress와 같은 전통적인 시스템과는 달리 콘텐츠 관리와 프론트엔드를 함께 번들하지 않습니다. 대신 Contentful은 구조화된 콘텐츠를 중앙에서 저장하고 API를 통해 필요한 모든 채널에 전달합니다.
핵심 개념은 디커플링된 아키텍처입니다. 콘텐츠는 Contentful의 클라우드에 저장됩니다. 프론트엔드(Next.js 사이트, React Native 앱, 또는 스마트 디스플레이 등)는 빌드 시점이나 런타임에 Contentful의 API를 통해 콘텐츠를 가져옵니다. 콘텐츠는 자신이 어디로 전달되는지 알거나 신경 쓰지 않습니다.
2013년 베를린에서 설립된 Contentful은 가장 큰 헤드리스 CMS 벤더 중 하나로 성장했습니다. Spotify, Vodafone, Chanel, Atlassian 같은 브랜드들이 Contentful에서 콘텐츠 운영을 합니다. 오픈 소스가 아니며 자체 호스팅 옵션도 없습니다. SaaS 형태만 제공되므로 데이터 거주지 관련 규정 준수 제약이 있다면 고려해야 할 사항입니다.
Contentful의 공식 문서에 따르면, 이 플랫폼은 자신을 콘텐츠의 인프라, 즉 편집팀과 디지털 경험 사이에 위치한 콘텐츠 허브로 자리매김하고 있습니다.
Contentful은 어떻게 작동하는가?
Contentful은 3계층 아키텍처를 따릅니다: 콘텐츠 모델(스키마)을 정의하고, 콘텐츠(엔트리)를 생성한 후 API를 통해 전달합니다. 콘텐츠는 채널에 독립적입니다. 즉, 같은 블로그 포스트가 중복 없이 웹사이트, 모바일 앱, 이메일 뉴스레터를 모두 운영할 수 있습니다.
모든 것이 API를 통해 흐릅니다. 내장된 서버 사이드 렌더링이 없고, 템플릿도 없고, 테마 레이어도 없습니다. 프론트엔드는 원하는 대로 빌드하고, Contentful은 콘텐츠 저장과 전달을 담당합니다.
세 가지 API
Contentful은 각각 고유한 목적과 인증을 가진 3가지 API를 제공합니다:
- 콘텐츠 전달 API(CDA): 게시된 콘텐츠에 대한 읽기 전용 액세스. Fastly CDN을 기반으로 하므로 캐시된 요청은 빠르고 제한이 없습니다. 캐시되지 않은 요청은 초당 55개로 제한됩니다.
- 콘텐츠 관리 API(CMA): 콘텐츠를 프로그래밍 방식으로 생성하고 업데이트하기 위한 읽기/쓰기 액세스. 초당 10개의 요청으로 제한됩니다. 마이그레이션, 대량 가져오기 또는 CI/CD 파이프라인에 사용합니다.
- 콘텐츠 미리보기 API(CPA): CDA와 동일하지만 초안 콘텐츠를 제공합니다. 프론트엔드에서 미리보기 모드를 구축하는 데 완벽합니다. 편집자들이 게시 전에 게시되지 않은 변경사항을 볼 수 있습니다.
세 가지 API 모두 REST와 GraphQL을 지원합니다. 인증은 Bearer 토큰을 통해 이루어지며, 전달 및 관리에 대한 별도의 토큰이 있습니다.
환경과 스페이스
스페이스를 프로젝트로, 환경을 콘텐츠에 대한 git 브랜치로 생각하세요. 프로덕션을 위한 마스터 환경과 편집자들이 라이브 콘텐츠에 영향을 주지 않고 작업할 수 있는 스테이징 환경을 가질 수 있습니다.
환경은 별칭 지정을 지원합니다. 마스터 별칭을 새 환경으로 지정하여 다운타임 없이 콘텐츠를 홍보할 수 있습니다. Contentful과 함께 사용할 프론트엔드 프레임워크를 선택하는 경우, 이 환경 모델은 Vercel 또는 Netlify와 같은 플랫폼에서의 미리보기 배포와 잘 작동합니다.
웹훅을 사용하면 콘텐츠가 변경될 때마다 빌드를 트리거하고, 외부 시스템과 동기화하거나, 워크플로우를 시작할 수 있습니다. 대부분의 팀은 이를 CI/CD 파이프라인에 연결하여 각 게시 이벤트마다 정적 사이트를 다시 빌드합니다.
Contentful의 콘텐츠 모델링
콘텐츠 모델링은 콘텐츠의 구조를 정의하는 곳입니다. 어떤 필드가 존재하는지, 어떤 유형의 데이터를 보유하는지, 콘텐츠 타입이 서로 어떻게 관련되는지를 결정하는 '스키마'입니다. 우리의 경험상, 이것이 바로 Contentful이 더 간단한 CMS 옵션보다 진정으로 돋보이는 부분입니다.
본질적으로 데이터베이스 테이블과 유사하지만 더 유연한 콘텐츠 스키마를 설계하고 있습니다. '블로그 포스트' 콘텐츠 타입은 제목(짧은 텍스트), 본문(리치 텍스트), 저자(저자 콘텐츠 타입에 대한 참조), 태그(문자열 배열)를 가질 수 있습니다. 생성하는 모든 엔트리는 이 구조를 따릅니다.
필드 타입 및 검증
Contentful은 견고한 범위의 필드 타입을 제공합니다:
- 짧은 텍스트(Symbol): 제목, 슬러그, 레이블 -- 최대 256자
- 긴 텍스트(Text): 마크다운 또는 일반 텍스트, 문자 제한 없음
- 리치 텍스트: JSON 기반(HTML이 아님), 완전한 렌더링 제어 제공
- 숫자: 정수 또는 소수
- 날짜/시간: ISO 8601 형식
- 부울: True/false 토글
- 미디어(Asset): 이미지, 비디오, 문서 -- Contentful의 자산 파이프라인에 저장됨
- 참조(Link): 엔트리를 다른 엔트리 또는 자산에 연결
- JSON 객체: 자유 형식의 구조화된 데이터
- 위치: 위도/경도 쌍
각 필드는 필수, 고유, 정규식 패턴, 크기 제한 및 사용자 정의 유효성 검사 메시지 등의 검증을 지원합니다. 편집자 UI에서 필드가 렌더링되는 방식을 제어하는 모양새 옵션도 설정할 수 있습니다.
참조 및 연결된 엔트리
참조는 콘텐츠 타입을 연결하는 방법입니다. 블로그 포스트의 '저자' 참조는 저자 엔트리에 연결됩니다. '관련 포스트' 필드는 여러 블로그 포스트 엔트리를 참조할 수 있습니다. 이는 콘텐츠 그래프를 생성합니다. 엔트리가 엔트리에 연결되어 있고 단일 API 호출로 쿼리 가능합니다.
콘텐츠 관리 API를 통해 생성할 때 블로그 포스트 콘텐츠 타입 정의가 실제로 어떻게 보이는지 다음과 같습니다:
이것은 버전 제어에 저장하고 마이그레이션 스크립트를 통해 적용하는 종류입니다. Contentful 가이드에서 이를 보여주는 경쟁사는 없습니다. 콘텐츠 모델링을 추상적으로 이야기할 뿐, 실제로 코드에서 어떻게 보이는지 보여주지 않습니다.
콘텐츠 쿼리: REST 및 GraphQL API
Contentful은 콘텐츠를 가져오기 위해 REST 및 GraphQL API를 모두 제공합니다. REST는 간단한 쿼리에 적합합니다. GraphQL은 중첩된 데이터가 필요하거나, 한 번의 요청으로 여러 콘텐츠 타입이 필요하거나, 과도한 데이터 가져오기를 피하고 싶을 때 더 좋습니다. 둘 다 동일한 인증 토큰을 사용합니다.
GraphQL 엔드포인트는 콘텐츠 모델에서 자동으로 생성됩니다. 생성하는 모든 콘텐츠 타입이 스키마에서 쿼리 가능한 타입이 되며, 필터링, 정렬, 페이지네이션이 내장되어 있습니다. 엔드포인트는 다음 위치에 있습니다:
Contentful의 GraphQL 문서에 따르면, 콘텐츠 타입을 수정할 때마다 스키마가 자동으로 업데이트됩니다. 수동 스키마 관리가 필요 없습니다.
GraphQL 쿼리 예시
다음은 최근 10개의 블로그 포스트와 저자들을 가져오는 기본 쿼리입니다:
태그로 필터링하고 독일어 콘텐츠를 가져와야 하나요? where 절과 locale 파라미터를 추가하세요:
주의할 사항이 있습니다: GraphQL 쿼리는 복잡도 제한이 있습니다. 깊게 중첩된 쿼리와 여러 개의 연결된 참조는 한계에 도달할 수 있습니다. Contentful은 노드의 수와 쿼리의 깊이를 기반으로 복잡도를 계산합니다. 블로그 포스트와 저자, 카테고리, 관련 포스트, 그리고 각 관련 포스트의 저자를 가져오고 있다면, 빠르게 누적됩니다.
REST API 기본 사항
REST API는 더 간단하지만 중첩된 데이터에 대해 더 많은 요청이 필요합니다. 블로그 포스트에 대한 기본 요청은 https://cdn.contentful.com/spaces/{SPACE_ID}/entries?content_type=blogPost 입니다. 플랫한 items 배열과 클라이언트 측에서 해결해야 할 연결된 엔트리에 대한 별도의 includes 객체가 있는 JSON을 얻습니다.
TypeScript를 사용 중이라면, Contentful의 contentful.js SDK는 링크 해결 및 타입 생성을 자동으로 처리합니다. 기본 fetch 호출의 경우, GraphQL API를 쿼리하는 최소한의 JavaScript는 다음과 같습니다:
그게 전부입니다. SDK가 필요 없고, 빌드 단계도 필요 없고, 의존성도 필요 없습니다. 이는 Node.js, Deno, Cloudflare Workers, 브라우저 등 HTTP 요청을 할 수 있는 어디서나 작동합니다.
알아두면 좋은 주요 기능
...