Contentful
들어가며
- Headless CMS 중 하나인 Contentful 서비스에 대하여 정리해본다.

Contentful
개념
- 2013년 독일 베를린에서 만들어진 Headless CMS(Content Management System, 컨텐츠 관리 시스템) 서비스
- 현재 Spotify, Red Bull, IKEA 등 굵직한 글로벌 기업들이 이 서비스를 이용하고 있다.
- 프론트엔드와 백엔드(컨텐츠 저장 및 관리)가 결합된 구조와 달리, 프론트엔드와 백엔드가 분리된 형태의 컨텐츠 관리 시스템이다.
Content that takes you everywhere
Business moves faster when teams producing content have a platform that empowers them to collaborate, innovate, and deliver impactful experiences at scale.
www.contentful.com
Headless CMS는 전통적인 CMS와 달리, 컨텐츠 관리(백엔드)와 컨텐츠 표시(프론트엔드)를 완전히 분리한 형태의 컨텐츠 관리 시스템이다. Headless CMS는 컨텐츠를 저장하고 관리하는 백엔드 기능만 제공하며, 이 컨텐츠를 어떤 형태로 보여줄지는 개발자가 프론트엔드 기술로 자유롭게 구현한다.
CMS(Content Management System)
- CMS와 관련된 자세한 내용은 아래의 게시글을 참고한다.
[Information] CMS(Content Management System)
CMS(Content Management System)들어가며CMS(Content Management System)에 대해 정리해본다. CMS(Content Management System)개념콘텐츠 관리 시스템웹사이트나 애플리케이션의 콘텐츠를 생성, 관리, 수정, 배포하는 데
dev-astra.tistory.com
특징
- 컨텐츠는 API(RESTful API 또는 GraphQL)를 통해 제공되며, 다양한 플랫폼(웹, 모바일, 앱, IoT 등)에서 재사용 가능하다.
- API를 통해 필요한 데이터만 가져오므로 로딩 속도가 빨라진다.
- API와 통신하기 위한 프론트엔드 개발 지식이 필요하다.
- 프론트엔드 개발자가 원하는 라이브러리 또는 프레임워크(React, Vue.js, Angular 등)를 사용해 UI를 구축할 수 있다.
- 하나의 컨텐츠를 다양한 채널(웹, 앱 등)에 맞게 배포할 수 있다.
- JSON, XML 등 구조화된 데이터를 반환하므로 다양한 환경에서 쉽게 통합이 가능하다.
사용 방법
- 리액트(React.js) 라이브러리와 Contentful를 연동하는 방법을 정리해본다.
1️⃣ Contentful 회원 가입하기
- Contentful 홈페이지에 접속하여 회원가입을 한다. (무료)
Content that takes you everywhere
Business moves faster when teams producing content have a platform that empowers them to collaborate, innovate, and deliver impactful experiences at scale.
www.contentful.com
Contentful 가격 플랜
Contentful Pricing
Scale our composable content platform in lock-step with your business, from your first digital experience to enterprise-wide content delivery across teams, channels and markets.
www.contentful.com

2️⃣ 컨텐츠 모델(Content Model) 생성하기
- Contentful 홈페이지에서 컨텐츠 모델(Content Model)을 생성해준다.
- 상단의
Content model]
탭을 클릭한 후,[Create content type]
버튼을 클릭한다.

Name
항목에 값을 입력해준다.

처음으로 컨텐츠 모델(Content Model)을 생성할 경우, 컨텐츠 모델 생성 후 바로 필드 타입(Field Type)을 생성할 수 있는 페이지로 넘어간다.
3️⃣ 필드 타입(Field Type) 생성하기
- 그리고 이어서 필드를 추가해준다.
- 필드 타입을 선택한 후, 필드 이름과 각 항목의 값을 입력해준다.
![]() |
![]() |
Contenful에서 제공하는 필드 타입
- 텍스트에 서식이 필요하면
Rich Text
, 간단한 텍스트라면Text
를 선택한다. - 컨텐츠 간 관계를 구축할 때는
Reference
를 선택한다. - 단순한 활성화/비활성화 스위치 기능이 필요할 경우
Boolean
을 선택한다. - 복잡하고 동적인 데이터를 처리할 때는
JSON Object
를 선택한다.
타입 | 설명 | 사용 예 |
Rich Text | - 서식이 있는 텍스트 - 미디어(이미지, 동영상 등) 포함 가능 - 다양한 기능 제공 (텍스트 스타일(Bold, Italic, Hyperlink), 목록, 표, 인라인 컨텐츠 참조(다른 컨텐츠와 연결) 등) |
- 블로그 본문 - 제품 설명 - FAQ 답변 |
Text | - 한 줄의 텍스트(Single Line Text) - 여러 줄의 텍스트(Long Text) |
- 제목, 이름, 짧은 설명 - 짧은 설명, 메모 |
Number | - 숫자 데이터 - 정수 및 소수 지원 |
- 제품 가격 - 재고 수량 - 순위(평점) |
Date and time | - 날짜 및 시간 데이터 - ISO 8601 형식 (예: 2024-11-28T15:30:00Z) |
- 이벤트 일정 - 게시 날짜 - 만료 시간 |
Location | - 지리적 데이터 - 위도 및 경도 |
- 매장 위치 - 지도 데이터 - 사용자 위치 |
Media | - 이미지, 비디오, 문서 등의 미디어 파일 | - 제품 사진 - PDF 메뉴얼 - 썸네일 이미지 |
Boolean | - 참/거짓 데이터 | - 공개 여부 - 기능 활성화 여부 - 조건에 따른 상태값 |
JSON Object | - JSON 형식의 구조화된 데이터 - 유연성이 높아, 비정형 데이터를 처리할 때 유용함. |
- 사용자 정의 데이터 - 다국어 키-값 매핑 - 복잡한 설정 값 |
Reference | - 다른 컨텐츠 항목(Entry)과의 관계 | - 블로그 작성자와 게시글 연결 - 제품과 카테고리 연결 - 이벤트와 위치 데이터 연결 |
- 추가적으로 유효성 검증(Validation), 기본값(Default Value), 모양(Appearance) 등 필드에 대한 설정을 해준다.

title
(Text),url
(Text),image
(Media) 필드를 생성해준다.

- 지금까지의 작업은 아래와 같은 객체(Object)의 키(Key)를 생성한 것과 같다.
const project = [ { title: 'project-1', url: 'https://example.com/1', image: './assets/apple.png' }, { title: 'project-2', url: 'https://example.com/2', image: './assets/banana.png' }, { title: 'project-3', url: 'https://example.com/3', image: './assets/carrot.png' }, ];
- 작업을 모두 마친 후,
[Save]
버튼을 클릭한다.

이미 생성한 컨텐츠 모델에 새로운 필드 타입 추가하기
- 만약, 이미 생성한 컨텐츠 모델에 새로운 필드 타입을 추가하려면, 상단의
[Content model]
탭을 클릭한 후, 새로운 필드 타입을 추가하고자 할 컨텐츠 모델 항목을 클릭한다.

- 그리고
[Add field]
버튼을 클릭한다.

4️⃣ 컨텐츠 엔트리(Entry) 생성하기
- Contentful에서 엔트리(Entry)는 컨텐츠 항목 하나를 의미한다.
- 컨텐츠를 구성하는 데이터의 실제 인스턴스이며, 컨텐츠 타입(Content Type)를 바탕으로 생성된다.
- 컨텐츠 타입(Content Type)은 컨텐츠의 구조(스키마)이고, 엔트리(Entry)는 그 구조에 맞춰 작성된 실제 데이터이다.
- 상단의
[Content]
탭을 클릭한 후,[Add entry]
버튼을 클릭한다.

- 다음과 같이 엔트리를 추가해줄 것이다.
const project = [ { title: 'project-1', url: 'https://example.com/1', image: './assets/apple.png' }, { title: 'project-2', url: 'https://example.com/2', image: './assets/banana.png' }, { title: 'project-3', url: 'https://example.com/3', image: './assets/carrot.png' }, ];
- 각 필드의 값들을 넣어주고 공개(Publish) 버튼을 클릭한다.
- 각 필드는 2️⃣에서 생성한 필드로 구성되어 있다.
- 이미지는 업로드 후, 따로 공개(Publish)를 해줘야 한다.
![]() |
![]() |
project-2
,project-3
의 엔트리도 추가해준다.

- 엔트리를 만들면서 업로드 했던 이미지들은, 상단의
[Media]
탭에서 확인할 수 있다.

5️⃣ Space ID와 API Key 값 확인 및 가져오기
- 로컬 프로젝트와 Contentful을 연결하기 위해서는 다음의 2가지가 필요하다.
☑️ Space ID
☑️ API Key (Access Token)
- 우측 상단의 설정 아이콘(⚙️)을 클릭한 후,
[API keys]
항목을 클릭한다.

- 기본적으로
Marketplace Apps Key
API Key가 발급되어 있다. - 추가적으로 API Key가 필요할 경우, 우측의
[Add API Key]
버튼을 클릭해서 생성해준다.

- 여기에서는 이미 생성되어 있는
Marketplace Apps Key
API Key를 이용하여 로컬 프로젝트와 연결할 것이다. Marketplace Apps Key
항목을 클릭한 후,Space ID
값과Content Delivery API - Access Token
값을 복사한다.

- 위에서 복사한 ①Space ID와 ②Access Token을 프로젝트 최상위 경로(
/
)의 환경 변수 파일(.env
)에 다음과 같이 넣어준다.- 환경 변수 파일(
.env
)이 없을 경우 새로 생성해준다.
- 환경 변수 파일(
/.env
VITE_API_KEY="YOUR_API_KEY" # REACT_APP_API_KEY="YOUR_API_KEY" VITE_SPACE_ID="YOUR_SPACE_ID" # REACT_APP_SPACE_ID="YOUR_SPACE_ID"
VITE 프로젝트일 경우VITE_
접두어를 키 이름 앞에 붙여주고, CRA(Create-React-App) 프로젝트일 경우REACT_APP_
접두어를 키 이름 앞에 붙여준다.
6️⃣ Contentful SDK 설치하기
공식 문서 확인하기
- 아래의 공식 문서 링크에 접속한 후, 자신의 플랫폼에 맞는 공식 문서를 보면서 진행한다.

View JavaScript SDK on GitHub
를 클릭한 후, 해당 페이지의 문서를 확인한다.
GitHub - contentful/contentful.js: JavaScript library for Contentful's Delivery API (node & browser)
JavaScript library for Contentful's Delivery API (node & browser) - contentful/contentful.js
github.com
![]() |
![]() |
여기에서는 JavaScript 플랫폼을 이용하여 진행한다.
API 레퍼런스 문서 확인하기
- Contentful에 대한 API 레퍼런스 문서는 아래의 링크를 참고한다.
API reference
API references for REST and GraphQL APIs for building applications | Content Delivery API | Content Management API | Content Preview API | Images API
www.contentful.com
![]() |
![]() |
SDK 라이브러리 설치하기
- 터미널에 아래 명령을 실행하여
contentful
라이브러리를 설치한다.
$ npm install contentful # yarn add contentful
7️⃣ Contentful에서 데이터(Entries) 가져오기
- 프로젝트의 최상단 경로(
/
)에/uitls
폴더를 생성한 후,fetchContentfulData.jsx
파일을 추가해준다. - 이 파일에 Contentful에서 생성한 엔트리 값들(Entries)을 가져오는 코드를 넣어줄 것이다.
- 아래의 공식 문서에 나와 있는 코드를 참고하여 코드를 작성해본다.
Content Delivery API
The Content Delivery API (CDA), is a read-only API for delivering content from Contentful to apps, websites and other media.
www.contentful.com
/utils/fetchContentfulData.jsx
- 클라이언트를 생성하는 코드를 작성한다.
import { createClient } from 'contentful'; // 클라이언트 생성하기 const client = createClient({ space: import.meta.env.VITE_SPACE_ID, // Space ID environment: 'master', accessToken: import.meta.env.VITE_API_KEY, // API Key (Access Token) });
CRA 프로젝트의 경우,process.env.REACT_APP_SPACE_ID
와process.env.REACT_APP_API_KEY
를 이용하여 Space ID와 API Key 값을 가져온다.
- 엔트리 데이터를 페칭하는 커스텀 훅을 만들어준다.
import { useState, useEffect } from 'react'; // ... export const useFetchContentfulEntries = () => { const [loading, setLoading] = useState(true); const [entries, setEntries] = useState([]); // 데이터 가져오기 const getData = async () => { try { const response = await client.getEntries({ content_type: 'Homepage', // 컨텐츠 모델(Content Model) 이름 }); // 응답된 값에서 데이터 추출 const data = response.items.map((item) => { const { title, url, image } = item.fields; const id = item.sys.id; // ID const img = image?.fields?.file?.url; return { title, url, id, img }; }); // 전역 변수에 저장 setEntries(data); setLoading(false); } catch (error) { console.log(error); setLoading(false); } }; // 화면이 처음 렌더링 될 때 데이터 페칭 useEffect(() => { getData(); }, []); return { loading, entries }; };
- 위 코드의
content_type
의 값은 2️⃣에서 생성한 컨텐츠 모델(Content Model)의Name
값을 넣어준다.

- 최종 코드는 아래와 같다.
import { useState, useEffect } from 'react'; import { createClient } from 'contentful'; // 클라이언트 생성하기 const client = createClient({ space: import.meta.env.VITE_SPACE_ID, // Space ID environment: 'master', accessToken: import.meta.env.VITE_API_KEY, // API Key (Access Token) }); export const useFetchContentfulEntries = () => { const [loading, setLoading] = useState(true); const [entries, setEntries] = useState([]); // 데이터 가져오기 const getData = async () => { try { const response = await client.getEntries({ content_type: 'Homepage', // 컨텐츠 모델(Content Model) 이름 }); // 응답된 값에서 데이터 추출 const data = response.items.map((item) => { const { title, url, image } = item.fields; const id = item.sys.id; // ID const img = image?.fields?.file?.url; return { title, url, id, img }; }); // 전역 변수에 저장 setEntries(data); setLoading(false); } catch (error) { console.log(error); setLoading(false); } }; // 화면이 처음 렌더링 될 때 데이터 페칭 useEffect(() => { getData(); }, []); return { loading, entries }; };
- 이제 필요한 컴포넌트에서 위에서 만든 커스텀 훅을 import 하여 데이터를 불러와 본다.
/src/components/MyComponent.jsx
import { useFetchContentfulEntries } from '../../utils/fetchContentfulData'; const MyComponent = () => { const { loading, entries } = useFetchContentfulEntries(); if (loading) { return ( <section className="projects"> <h2>Loading...</h2> </section> ); } return ( <section className="projects"> <div className="title"> <h2>projects</h2> <div className="title-underline"></div> </div> <div className="projects-center"> {entries.map((item) => { const { id, img, url, title } = item; return ( <a key={id} href={url} target="_blank" rel="noreferer" className="project" > <img src={img} alt={title} className="img" /> <h5>{title}</h5> </a> ); })} </div> </section> ); }; export default MyComponent;
참고 사이트
Contentful - Wikipedia
From Wikipedia, the free encyclopedia Headless CMS Contentful is a headless content management system (CMS), founded in 2013 in Berlin, Germany, by Sascha Konietzke and Paolo Negri. The company and the platform are both called Contentful.[2] As of June 202
en.wikipedia.org
API reference
API references for REST and GraphQL APIs for building applications | Content Delivery API | Content Management API | Content Preview API | Images API
www.contentful.com
'DevOps > Service' 카테고리의 다른 글
[Service] Auth0 (2) | 2024.11.20 |
---|---|
[Service] Render (0) | 2024.11.06 |
[Service] Mockaroo (2) | 2024.11.06 |
[Service] 프리즈마(Prisma) (3) | 2024.10.22 |
[Service] Supabase (1) | 2024.10.21 |