Backend
Sanity vs. Strapi: Headless CMS를 고를 때 실제로 고민했던 것들
Sanity와 Strapi는 모두 좋은 Headless CMS지만, 콘텐츠를 저장하고 운영하는 방식은 꽤 다릅니다. 두 CMS의 구조와 개발 경험, 운영 부담을 비교해 봅니다.
웹사이트를 만들다 보면 어느 순간 콘텐츠 관리가 문제가 됩니다.
처음에는 Markdown 파일 몇 개로 충분합니다. 그런데 글이 늘어나고, 작성자가 개발자 한 명에서 여러 명으로 늘어나고, 이미지나 카테고리, 태그, SEO 정보까지 관리하기 시작하면 이야기가 달라집니다.
이쯤에서 자연스럽게 Headless CMS를 찾게 됩니다.
그리고 후보를 조사하다 보면 꽤 높은 확률로 Sanity와 Strapi를 만나게 됩니다.
둘 다 콘텐츠와 프론트엔드를 분리하고 API를 통해 데이터를 제공한다는 점에서는 비슷합니다. Next.js, Nuxt, Astro 같은 프레임워크와도 잘 어울립니다.
하지만 실제로 사용해 보면 두 제품이 해결하려는 문제의 방향은 꽤 다릅니다.
한 문장으로 먼저 정리하면 다음과 같습니다.
Sanity는 "콘텐츠 플랫폼을 서비스로 사용한다"는 느낌에 가깝고, Strapi는 "내가 소유하고 운영하는 CMS 백엔드를 만든다"는 느낌에 가깝습니다.
이 차이를 이해하면 선택이 훨씬 쉬워집니다.
먼저, Headless CMS가 필요한 이유
전통적인 CMS에서는 콘텐츠 관리와 화면 렌더링이 하나의 시스템 안에 있는 경우가 많았습니다.
Headless CMS는 이 둘을 분리합니다.
Traditional CMS
Content
↓
CMS
↓
Template / Rendering
↓
Website
Headless CMS
Content
↓
CMS
↓
API
↓
Next.js / Nuxt / App / Other Services
CMS는 콘텐츠를 관리하고 API로 제공하는 역할에 집중합니다.
프론트엔드는 그 데이터를 가져와 원하는 방식으로 표현합니다.
덕분에 하나의 콘텐츠를 웹사이트뿐 아니라 모바일 앱, 이메일, 디지털 사이니지, 내부 서비스 등 여러 채널에서 재사용하기 쉬워집니다.
Sanity와 Strapi 모두 이 기본적인 Headless CMS 구조를 지원합니다.
차이는 CMS 자체를 누가 얼마나 관리하느냐에서 시작합니다.
Sanity: 콘텐츠 인프라를 서비스로 사용하기
Sanity의 핵심에는 Content Lake가 있습니다.
콘텐츠는 구조화된 JSON document 형태로 Content Lake에 저장되고, 애플리케이션에서는 API나 SDK를 이용해 데이터를 조회합니다. Sanity는 이를 단순 CMS보다는 콘텐츠를 위한 데이터 플랫폼에 가까운 형태로 설명하고 있습니다.
구조를 단순화하면 다음과 같습니다.
Sanity Studio
│
▼
Sanity APIs
│
▼
Content Lake
│
▼
GROQ / GraphQL / Client
│
▼
Next.js
여기서 재미있는 부분은 Sanity Studio와 실제 콘텐츠 저장소가 분리되어 있다는 점입니다.
Studio는 React 기반의 오픈소스 SPA이고, 직접 호스팅하거나 Sanity에서 제공하는 호스팅을 사용할 수 있습니다. 반면 실제 콘텐츠는 Sanity의 hosted API와 Content Lake에 연결됩니다.
그래서 개발자가 데이터베이스 서버를 직접 만들고 운영하는 느낌은 상대적으로 적습니다.
Sanity의 Schema as Code
개인적으로 Sanity를 사용할 때 가장 인상적인 부분 중 하나는 콘텐츠 스키마를 코드로 관리하는 방식입니다.
예를 들어 기술 블로그의 글을 정의한다면 다음과 같이 작성할 수 있습니다.
import {defineField, defineType} from "sanity"
export const techNote = defineType({
name: "techNote",
title: "Technical Note",
type: "document",
fields: [
defineField({
name: "title",
type: "string",
validation: (Rule) => Rule.required(),
}),
defineField({
name: "slug",
type: "slug",
options: {
source: "title",
},
}),
defineField({
name: "publishedAt",
type: "datetime",
}),
],
})
콘텐츠 구조가 Git repository 안에 코드로 존재하기 때문에 변경 사항을 코드 리뷰할 수 있습니다.
schema 변경
↓
Git commit
↓
Pull Request
↓
Code Review
↓
Deploy Studio
개발팀 입장에서는 상당히 자연스러운 workflow입니다.
특히 여러 개발자가 콘텐츠 모델을 관리한다면 "누가 production CMS에서 필드를 하나 추가했는데 코드에는 없다"와 같은 상황을 줄이기 좋습니다.
다만 한 가지 알아둘 점도 있습니다.
Sanity의 schema validation은 Studio에서 실행되며 Content Lake 서버 자체가 해당 schema를 강제하는 것은 아닙니다. API나 client를 통해 직접 데이터를 쓰는 경우 Studio의 validation rule이 자동으로 적용되는 구조는 아닙니다. Content Lake가 의도적으로 schemaless하게 동작하기 때문입니다.
이 특성은 schema evolution을 유연하게 만들지만, 외부 시스템에서 데이터를 직접 쓰는 경우 별도의 validation 전략을 고려해야 합니다.
Strapi: CMS 자체가 하나의 Backend Application
Strapi의 접근 방식은 조금 다릅니다.
Strapi를 설치하면 실제로 Node.js 기반의 backend application이 만들어집니다.
Strapi Admin
│
▼
Strapi Backend
│
┌────┴────┐
▼ ▼
REST GraphQL
│
▼
PostgreSQL
│
▼
Next.js
즉 Strapi 자체가 여러분의 backend입니다.
공식적으로 Strapi Community Edition은 MIT 라이선스의 오픈소스로 제공되며, 직접 서버나 AWS, Azure, GCP, VPS, Docker, Kubernetes 또는 on-premise 환경에 배포할 수 있습니다. PostgreSQL, MySQL, MariaDB 등을 직접 연결할 수도 있습니다.
이 구조의 가장 큰 장점은 명확합니다.
내가 전부 제어할 수 있습니다.
Database도 내 것.
Server도 내 것.
Backend code도 내 것.
Infrastructure도 내 것.
필요하다면 controller, service, middleware를 작성해 일반적인 CMS 범위를 넘어서는 backend logic도 구현할 수 있습니다.
가장 큰 차이: Managed Platform vs. Owned Backend
두 제품의 차이를 가장 단순하게 표현하면 다음과 같습니다.
Sanity
Frontend
│
▼
Sanity Client
│
▼
Sanity Managed Content Infrastructure
Strapi
Frontend
│
▼
REST / GraphQL
│
▼
Your Strapi Server
│
▼
Your Database
Sanity에서는 콘텐츠 인프라 운영의 상당 부분을 Sanity가 담당합니다.
Strapi에서는 직접 self-hosting한다면 서버, database, backup, scaling, monitoring 등을 개발팀이 관리합니다.
물론 Strapi에도 Strapi Cloud가 있습니다.
Strapi Cloud를 이용하면 PostgreSQL database, CDN, email, backup 등을 포함한 managed hosting을 사용할 수 있으므로 반드시 직접 infrastructure를 관리해야 하는 것은 아닙니다.
따라서 현재의 Strapi를 단순히 "self-hosted CMS"라고 설명하는 것은 정확하지 않습니다.
좀 더 정확하게 표현하면:
Sanity
→ Managed content infrastructure가 기본 철학
Strapi
→ Self-host와 managed Strapi Cloud 중 선택 가능
입니다.
Content Modeling은 어떻게 다른가
두 CMS 모두 structured content를 만들 수 있지만 개발 경험은 다릅니다.
Sanity에서는 앞서 본 것처럼 schema를 코드로 정의하는 접근이 중심입니다.
반면 Strapi에서는 Content-Type Builder를 통해 Admin UI에서 content type과 field를 구성하는 경험이 매우 편리합니다. Strapi는 정의된 모델을 기반으로 REST와 GraphQL API를 생성합니다.
예를 들어 다음 모델을 만든다고 해보겠습니다.
Article
├─ title
├─ slug
├─ content
├─ author
├─ category
└─ publishedAt
Sanity에서는 개발자가 schema code를 작성하는 흐름이 자연스럽습니다.
Developer
↓
Schema Code
↓
Studio
↓
Content
Strapi에서는 UI 중심의 흐름도 자연스럽습니다.
Developer / Admin
↓
Content-Type Builder
↓
Database Model
↓
REST / GraphQL API
어느 방식이 더 좋은지는 팀의 성격에 따라 다릅니다.
개발자가 콘텐츠 구조까지 적극적으로 관리한다면 Sanity 방식이 상당히 매력적입니다.
반대로 CMS 관리 화면에서 모델을 빠르게 만들고 바로 API를 제공하고 싶다면 Strapi가 직관적입니다.
GROQ는 Sanity의 꽤 강력한 무기
Sanity를 이야기할 때 빼놓기 어려운 것이 GROQ(Graph-Relational Object Queries) 입니다.
Sanity Content Lake에서는 GROQ를 사용해 필요한 JSON 구조를 직접 projection할 수 있습니다. GraphQL도 사용할 수 있지만 GROQ가 Sanity의 대표적인 query 방식입니다.
예를 들어 다음처럼 사용할 수 있습니다.
*[
_type == "techNote" &&
category == "backend"
] | order(publishedAt desc) {
title,
slug,
publishedAt,
"author": author->name
}
응답에 필요한 형태를 query 단계에서 꽤 자유롭게 만들 수 있습니다.
Frontend 입장에서는 편합니다.
Content Lake
│
│ GROQ
▼
Exactly the JSON
the frontend needs
반면 Strapi는 개발자에게 익숙한 REST 및 GraphQL 중심의 API 경험을 제공합니다.
REST API에 익숙한 팀이라면 Strapi가 처음에는 훨씬 친숙할 가능성이 높습니다.
Sanity의 GROQ는 처음에는 새로운 문법을 배워야 한다는 비용이 있지만, 익숙해지고 나면 복잡한 structured content를 조회할 때 상당히 편리합니다.
Editor Experience
CMS를 선택할 때 개발자 경험만 보면 안 됩니다.
실제로 매일 CMS를 사용하는 사람은 콘텐츠 에디터일 가능성이 높기 때문입니다.
이 부분에서는 Sanity가 흥미로운 특징을 가지고 있습니다.
Sanity Studio는 React 기반으로 만들어져 있기 때문에 필요하면 editing interface 자체를 프로젝트에 맞게 상당히 깊게 customize할 수 있습니다. Sanity는 real-time collaborative editing도 주요 기능으로 제공하고 있습니다.
예를 들어 단순히 이런 form을 제공하는 데서 끝나지 않고,
Title [ ]
Category [ Backend ▼ ]
Body [ ]
[ ]
Publish [ Button ]
도메인에 맞는 editing experience를 만들 수 있습니다.
Product Editor
┌───────────────────────────────┐
│ Product Preview │
│ │
│ [ Product Image ] │
│ │
│ Name MacBook Pro │
│ Market Korea │
│ Status ● Published │
└───────────────────────────────┘
CMS를 단순한 admin panel이 아니라 사내 콘텐츠 도구처럼 발전시키려는 팀에게는 큰 장점입니다.
Strapi 역시 admin panel과 backend를 확장할 수 있으며 plugin과 custom backend logic을 지원합니다.
다만 기본 철학에는 차이가 있습니다.
Sanity는 Studio 자체를 개발자가 적극적으로 구성하는 방향이 강하고, Strapi는 비교적 익숙한 CMS admin experience에서 시작해 필요한 부분을 확장하는 느낌에 가깝습니다.
Infrastructure를 누가 책임질 것인가
실제 프로젝트에서는 이 질문이 굉장히 중요합니다.
예를 들어 self-hosted Strapi를 운영한다고 해보겠습니다.
그러면 CMS를 선택한 것과 동시에 다음 문제들도 따라옵니다.
Application Server
Database
Object Storage
CDN
Backup
Monitoring
Logging
Security Updates
Scaling
Deployment
물론 AWS와 Docker/Kubernetes에 익숙한 팀이라면 오히려 장점입니다.
모든 infrastructure를 직접 통제할 수 있기 때문입니다.
특히 다음과 같은 요구사항이 있다면 Strapi의 self-hosting은 강력합니다.
Data must stay inside our VPC.
Database must be PostgreSQL.
CMS must run on-premise.
We need custom backend logic.
We need complete infrastructure control.
Strapi는 자체 infrastructure나 isolated network에서도 운영할 수 있고 database 역시 직접 선택할 수 있습니다.
반대로 작은 개발팀에서 CMS 하나를 위해 database와 server를 계속 운영하고 싶지 않다면 이야기가 달라집니다.
이 경우 Sanity의 managed infrastructure가 상당히 매력적입니다.
Vendor Lock-in도 생각해야 한다
Sanity를 선택할 때 고려할 부분 중 하나는 platform dependency입니다.
Studio 자체는 open-source React application이고 별도로 호스팅할 수 있지만, 콘텐츠 저장 계층은 Sanity Content Lake와 hosted APIs를 중심으로 동작합니다.
즉 애플리케이션이 다음 요소에 점점 의존하게 될 수 있습니다.
Sanity Content Lake
GROQ
Portable Text
Sanity APIs
Sanity Client
이것 자체가 나쁜 것은 아닙니다.
AWS를 사용하면 AWS ecosystem에 의존하고, Firebase를 사용하면 Firebase ecosystem에 의존하는 것과 비슷한 trade-off입니다.
중요한 것은 이 dependency를 알고 선택하는 것입니다.
Strapi에서는 상황이 조금 다릅니다.
Community Edition 자체가 MIT-licensed open source이고 database와 infrastructure를 직접 소유할 수 있기 때문에 architecture control과 portability 측면에서 상대적으로 유리합니다.
그래서 어떤 것을 선택하면 좋을까?
결국 선택 기준은 기능의 개수보다 팀이 무엇을 소유하고 싶은가에 가깝다고 생각합니다.
Sanity가 잘 맞는 경우
✓ CMS infrastructure를 직접 운영하고 싶지 않다.
✓ 콘텐츠 모델을 코드로 관리하고 싶다.
✓ 실시간 협업이 중요하다.
✓ 복잡한 structured content를 다룬다.
✓ GROQ의 flexible query가 매력적이다.
✓ CMS UI를 product처럼 customize하고 싶다.
특히 작은 개발팀에서 빠르게 제품을 만들고 콘텐츠 infrastructure 운영에 시간을 쓰고 싶지 않다면 Sanity가 좋은 선택이 될 수 있습니다.
Strapi가 잘 맞는 경우
✓ CMS와 database를 직접 소유하고 싶다.
✓ Self-hosting이 필요하다.
✓ 기존 PostgreSQL/MySQL infrastructure를 활용하고 싶다.
✓ REST/GraphQL 중심의 backend가 익숙하다.
✓ CMS에 custom backend logic이 많이 필요하다.
✓ Data residency 또는 내부 infrastructure 요구사항이 강하다.
특히 이미 backend/DevOps 역량이 있는 조직이라면 Strapi의 자유도가 큰 장점이 됩니다.
한눈에 비교하기
| 항목 | Sanity | Strapi |
|---|---|---|
| 기본 성격 | Managed content platform | Open-source CMS/backend |
| Content storage | Sanity Content Lake | SQL database |
| Self-host CMS backend | 제한적 | 가능 |
| Studio/Admin hosting | Hosted 또는 self-host | Strapi app과 함께 운영 / Cloud |
| Schema | Code 중심 | Admin UI + project configuration |
| Query | GROQ, GraphQL 등 | REST, GraphQL |
| Database 관리 | Sanity가 관리 | 직접 관리 또는 Strapi Cloud |
| Backend customization | Content platform/Studio 중심 | Controller, Service, Middleware 등 |
| Real-time collaboration | 강점 | 전통적인 CMS workflow 중심 |
| Infrastructure control | 상대적으로 낮음 | 높음 |
| 운영 부담 | 상대적으로 낮음 | Self-host 시 높음 |
| Open-source 성격 | Studio가 open source | CMS 전체가 MIT open source |
내가 프로젝트를 시작한다면
개인 기술 블로그나 작은 SaaS의 콘텐츠 시스템을 만든다면 저는 먼저 Sanity를 검토할 것 같습니다.
이유는 단순합니다.
CMS 하나 때문에 database와 backend infrastructure를 추가로 운영하고 싶지 않기 때문입니다.
Next.js
+
Sanity
+
Vercel
정도의 구조만으로도 꽤 많은 콘텐츠 기반 서비스를 만들 수 있습니다.
반대로 회사 내부 시스템이고 이미 다음과 같은 infrastructure가 존재한다면 판단이 달라집니다.
AWS
├─ ECS / Kubernetes
├─ RDS PostgreSQL
├─ S3
├─ CloudFront
└─ Monitoring
여기에 CMS를 넣는 상황이라면 Strapi가 훨씬 자연스러울 수 있습니다.
특히 데이터가 외부 SaaS에 저장되면 안 되는 요구사항이 있다면 Strapi self-hosting의 장점은 더욱 명확해집니다.
마치며
Sanity와 Strapi를 비교하면 처음에는 둘 다 비슷한 Headless CMS처럼 보입니다.
하지만 조금 더 깊이 들어가면 철학이 다릅니다.
Sanity는 질문합니다.
"콘텐츠 infrastructure를 직접 운영할 필요가 있을까?"
Strapi는 반대 방향의 질문에 가깝습니다.
"CMS도 결국 우리 backend인데, 우리가 직접 소유하면 안 될까?"
그래서 단순히 feature checklist만 비교해서 선택하기는 어렵습니다.
제가 생각하는 가장 좋은 판단 기준은 다음 질문입니다.
우리 팀은 콘텐츠 infrastructure를 서비스로 사용하고 싶은가, 아니면 backend application으로 직접 소유하고 싶은가?
전자가 중요하다면 Sanity가 자연스럽습니다.
후자가 중요하다면 Strapi가 자연스럽습니다.
결국 좋은 Headless CMS는 기능이 가장 많은 CMS가 아니라, 우리 팀이 책임지고 싶은 영역과 책임지고 싶지 않은 영역을 가장 잘 나눠주는 CMS라고 생각합니다.
Tags