SvelteKit 헤드리스 CMS 가이드: Directus·Strapi·Sanity·Payload

Svelte·SvelteKit과 헤드리스 CMS: Directus, Strapi, Sanity, Payload 선택과 연결

헤드리스 CMS는 콘텐츠 편집 화면과 콘텐츠를 보여 주는 프런트엔드를 분리한다. SvelteKit은 그 콘텐츠를 받아 라우트와 페이지로 렌더링하는 역할을 맡는다. 이 조합의 장점은 한 번 만든 콘텐츠를 웹, 앱, 뉴스레터 등 여러 채널에서 재사용할 수 있다는 데 있다. 반면 CMS를 고른다고 콘텐츠 모델, 권한, 미리보기, 캐시가 자동으로 해결되지는 않는다. 먼저 어떤 사람이 어떤 콘텐츠를 어떤 상태에서 편집하고, 방문자에게는 어느 시점의 데이터가 보여야 하는지 결정해야 한다.

SvelteKit 쪽의 기본 구조

SvelteKit의 load 함수는 페이지가 필요한 데이터를 가져와 컴포넌트에 전달하는 표준 흐름이다. 공개 글 목록과 상세 글처럼 SEO가 중요한 페이지는 서버 load에서 CMS를 조회해 렌더링에 필요한 최소 필드를 넘기는 패턴이 실용적이다. 브라우저에 비밀 토큰을 두면 안 되는 요청, 초안 미리보기, 권한이 필요한 콘텐츠는 서버에서 처리한다. 클라이언트 load나 브라우저 fetch는 로그인 후 상호작용처럼 공개해도 되는 요청에 한정한다.

// src/routes/posts/[slug]/+page.server.ts
export const load = async ({ params, fetch, setHeaders }) => {
  const res = await fetch(`${CMS_URL}/posts?slug=${encodeURIComponent(params.slug)}`);
  if (!res.ok) throw error(res.status, 'Post not found');
  setHeaders({ 'cache-control': 'public, max-age=60' });
  return { post: await res.json() };
};

위 코드는 개념 예시다. 실제 API 형식, 권한, 캐시 헤더는 선택한 CMS와 배포 플랫폼에 맞춰야 한다. 특히 외부 응답을 그대로 HTML로 주입하지 말고, Portable Text·Rich Text·Markdown 등 콘텐츠 형식마다 검증되고 유지되는 렌더러를 둔다. slug는 콘텐츠의 안정적인 공개 식별자로 취급하고 변경·리다이렉트·중복을 편집 흐름으로 관리한다.

네 가지 CMS가 다른 지점

Directus는 기존 또는 새 데이터베이스 위에 데이터와 권한, API를 제공하는 접근에 가깝다. 데이터 모델을 관계형 테이블 중심으로 운영하고 REST 또는 GraphQL로 읽고 싶다면 잘 맞을 수 있다. Strapi는 콘텐츠 타입을 만들면 Content API 엔드포인트를 자동 생성한다. Strapi 5의 REST API는 문서, 로케일, draft/published 상태를 다루며, 관계·미디어는 기본 응답에 항상 채워지지 않으므로 필요한 populate을 명시해야 한다.

Sanity는 구조화된 JSON 문서를 Content Lake에 저장하고, 기본 질의 언어인 GROQ로 필요한 모양의 응답을 구성한다. GraphQL API도 스키마에서 생성·배포할 수 있지만, Sanity 문서는 GROQ를 우선 검토하도록 안내한다. Payload는 애플리케이션 코드와 가까운 CMS를 원하는 팀에 해당한다. REST, Local API, GraphQL API를 제공하며, REST의 기본 경로와 인가·로케일 처리 방식은 프로젝트 설정에서 확인해야 한다. 어느 쪽도 “무조건 더 빠른 CMS”라고 일반화할 수 없다. 데이터 모델, 콘텐츠 양, 이미지 전송, 캐시, 배포 위치가 실제 지연을 결정한다.

운영에서 먼저 설계할 것

  1. 콘텐츠 계약: 제목, slug, 본문 블록, SEO, 작성자, 게시 상태, 로케일을 TypeScript 타입과 CMS 스키마 양쪽에 명시한다.
  2. 공개/비공개 경계: 공개 API에는 필요한 읽기 권한만, 편집·미리보기·웹훅에는 서버 전용 비밀값과 검증을 둔다.
  3. 미리보기: 초안을 보려면 CMS의 draft 식별과 SvelteKit의 보호된 preview 경로를 연결하고, 일반 캐시와 섞이지 않게 한다.
  4. 캐시 무효화: 게시·수정 웹훅을 검증한 뒤 관련 경로만 재검증하거나 CDN 캐시 키를 갱신한다. 웹훅은 공개 URL이므로 서명 검증과 재전송 처리도 필요하다.
  5. 실패 경험: CMS 지연·오류 시 404와 500을 구분하고, 마지막으로 검증된 공개 콘텐츠를 보여 줄 수 있는지 정책을 정한다.

선택 기준

이미 SQL 데이터와 데이터 관리 요구가 강하면 Directus, Node 기반 콘텐츠 타입과 플러그인 흐름이 맞으면 Strapi, 편집 경험과 콘텐츠 질의 형태의 유연성이 핵심이면 Sanity, 애플리케이션 코드 안에서 CMS를 강하게 제어하고 싶으면 Payload를 검토할 수 있다. 하지만 이름만 보고 고르지 말자. 대표 콘텐츠 모델 하나, 목록·상세·초안 미리보기 한 흐름, 권한 두 종류, 웹훅 한 개를 작은 검증 프로젝트로 만든 뒤 편집자와 개발자가 함께 확인하는 편이 안전하다.

대표 출처

https://svelte.dev/docs/kit/load
https://docs.directus.io/guides/connect/
https://docs.strapi.io/cms/api/rest

koen