왜 이 글을 쓰게 되었나
이전 글에서도 말했듯이, 나는 Strapi Cloud를 이용해 블로그 데이터를 관리해왔다.
월 2만원가량 내면서 "이게 과연 가치가 있나?" 고민도 했었고,
결국 로컬 MDX 파일로 전환하는 결정을 내리기도 했다.
그런데 돌이켜보면, Strapi Cloud + Next.js 조합으로 블로그를 운영하면서
정말 많은 것을 배웠다는 걸 느꼈다.
단순히 "블로그 하나 만들었다"가 아니라, 풀스택 아키텍처를 직접 설계하고 운영한 경험이었다.
그래서 까먹기 전에 한 번 정리해보려 한다.
Headless CMS, 직접 써보니 이런 거였다
프론트와 백엔드의 완전한 분리
Strapi는 콘텐츠 API만 제공하고, Next.js가 화면을 담당한다.
처음엔 "그냥 풀스택 프레임워크 하나 쓰면 되지 않나?" 싶었는데,
막상 분리해보니 각각 독립적으로 배포하고 업데이트할 수 있다는 게 꽤 편했다.
프론트엔드 디자인을 갈아엎어도 백엔드는 건드릴 필요가 없고,
Strapi 설정을 바꿔도 프론트는 API 응답 형식만 맞으면 그만이었다.
콘텐츠 모델링의 자유
Post, Category, Tag 세 개의 컬렉션 타입을 직접 설계했다.
Category는 self-reference로 계층 구조를 지원하게 만들었고,
Tag는 Post와 다대다 관계로 연결했다.
Post에는 featuredImage, postStatus enum 같은 커스텀 필드도 자유롭게 추가했다.
이 과정에서 관계형 데이터 모델링을 직접 해보는 경험이 생겼고,
프론트엔드 개발자로서 백엔드의 데이터 구조를 이해하는 시야가 넓어졌다.
Strapi Cloud가 줬던 편리함
인프라 걱정 제로
Dockerfile도, CI/CD 파이프라인도 필요 없었다.
npm run deploy 한 줄이면 배포 끝.
백엔드를 처음 다뤄보는 프론트엔드 개발자에게 이 진입장벽의 낮음은 정말 큰 장점이었다.
관리자 패널이 기본
별도로 어드민 페이지를 만들 필요 없이, Strapi Admin에서 콘텐츠 CRUD, 사용자 권한, 미디어 관리가 다 됐다.
Draft & Publish 기능도 기본 내장이라 글을 미리 써두고 원하는 시점에 발행하는 것도 자연스러웠다.
인증도 기본 제공
@strapi/plugin-users-permissions 플러그인으로 JWT 기반 인증과 역할별 권한 관리가 바로 사용 가능했다.
인증 시스템을 직접 구현하는 건 시간도 많이 들고 보안 이슈도 걱정되는데,
이 부분을 Strapi가 해결해줘서 콘텐츠와 프론트엔드에 집중할 수 있었다.
Next.js 15에서 배운 것들
ISR이 블로그에 최적이었다
ISR(Incremental Static Regeneration)을 5분 간격으로 설정했다.
정적 사이트 수준의 빠른 로딩 속도를 유지하면서도, 콘텐츠 변경이 자동으로 반영되는 구조.
빌드 시 전체 페이지를 생성하지 않고 on-demand로 처리하니 배포 시간도 짧았다.
posts, post-${slug}, categories, tags 같은 태그 기반 캐시 무효화를 적용해서
변경된 콘텐츠만 선택적으로 revalidation하는 것도 직접 구현해봤다.
이 경험이 캐싱 전략에 대한 감을 잡는 데 많은 도움이 됐다.
API Route를 프록시로 활용하기
Next.js의 API Route(/api/auth, /api/posts 등)가 Strapi API의 프록시 역할을 하도록 구성했다.
클라이언트에 Strapi 엔드포인트를 직접 노출하지 않으니 보안적으로 안심이 됐고,
나중에 백엔드를 교체하더라도 프론트엔드 변경이 최소화된다는 장점도 있었다.
실제로 Strapi Cloud에서 로컬 MDX로 전환할 때 이 구조 덕분에 훨씬 수월했다.
Server Components와 Client Components의 분리
데이터 페칭은 Server Component에서, 인터랙션(에디터, 테마 토글)은 Client Component에서 처리했다.
이 분리를 통해 클라이언트 번들 사이즈를 줄이고, 서버에서 가능한 작업은 서버에서 처리하는 습관이 생겼다.
SEO, 직접 해보니 생각보다 할 게 많았다
동적 메타데이터
Next.js Metadata API로 각 포스트별 OpenGraph, Twitter Card를 자동 생성했다.
1200x630 사이즈의 OG 이미지도 설정했고, JSON-LD로 BlogPosting 스키마도 넣었다.
검색엔진에 글의 작성자, 발행일, 수정일 같은 구조화된 정보를 제공하는 건
처음 해봤는데, SEO가 단순히 키워드 넣기가 아니라는 걸 체감했다.
사이트맵과 RSS
1000+ 포스트를 지원하는 동적 사이트맵을 구현했고,
RSS 2.0 피드도 자동 생성되게 만들었다.
Tiptap JSON을 평문으로 변환해서 RSS description에 넣는 부분은 은근 까다로웠지만,
이런 세부적인 것들이 쌓여서 검색 노출이 되는 거구나 싶었다.
에디터, 직접 만드는 재미
Tiptap(ProseMirror 기반) WYSIWYG 에디터를 프론트엔드에 직접 구현했다.
코드 블록 신택스 하이라이팅은 Lowlight로 JS, TS, Python 등 9개 언어를 지원하게 했고,
이미지는 browser-image-compression으로 업로드 전 클라이언트에서 압축 처리했다.
콘텐츠를 JSON 형태로 저장하니 다양한 형태로 렌더링할 수 있다는 것도 장점이었다.
HTML로 변환, 평문으로 변환, 첫 이미지 자동 추출 등 여러 유틸리티를 만들면서
콘텐츠를 데이터로 다루는 감각이 생긴 것 같다.
분석 도구는 처음부터 넣는 게 맞다
Google Analytics 4와 Vercel Analytics를 같이 붙였다.
단순 페이지뷰가 아니라 view_post, complete_reading, search, change_theme 같은
블로그 특화 커스텀 이벤트를 트래킹하게 만들었다.
스크롤 깊이와 읽기 시간도 측정하니, 어떤 글이 끝까지 읽히는지 데이터로 보인다.
이건 나중에 넣으려면 귀찮아지니까, 처음부터 세팅해두는 게 맞다고 느꼈다.
상태 관리와 데이터 페칭
TanStack React Query v5를 도입했다.
staleTime 5분, gcTime 10분으로 설정해서 불필요한 API 호출을 최소화했고,
포스트 생성/수정/삭제 시 캐시를 자동으로 무효화하도록 구성했다.
인증 상태는 Context API로 전역 관리하고, ProtectedRoute 컴포넌트로 라우트를 보호했다.
이런 클라이언트 상태 관리 패턴을 직접 설계해보면서
"어디까지 서버 상태이고, 어디부터 클라이언트 상태인가"에 대한 기준이 잡혔다.
보안, 개인 프로젝트라도 신경 쓰자
CORS를 localhost:3000과 mykim.in 도메인만 허용하도록 제한했고,
인증 토큰은 HttpOnly 쿠키에 저장해서 XSS 공격으로부터 보호했다.
환경 변수도 .env, .env.local, .env.production으로 분리 관리했다.
개인 프로젝트라 대충 하고 싶은 유혹이 있었지만,
이런 보안 습관은 회사 프로젝트에서도 그대로 적용되니 연습한다고 생각했다.
개발 생산성을 높여준 도구들
- shadcn/ui + Radix UI: 접근성 보장된 UI 컴포넌트를 빠르게 조립. 디자인 시스템 없이도 일관된 UI 가능
- Turbopack: Next.js 15의 개발 서버. HMR이 확실히 빨라졌다
- Jest + Testing Library + MSW: API 모킹 기반 테스트로 안정성 확보
- ESLint + Prettier + Husky: pre-commit hook으로 코드 품질을 자동화
- TypeScript 전면 적용: 프론트엔드, 백엔드 모두. Strapi의 자동 생성 타입과 프론트엔드 타입의 일관성 유지
배포, 이렇게 편할 수가
Strapi Cloud + Vercel 조합은 배포 경험이 정말 좋았다.
백엔드는 npm run deploy, 프론트엔드는 git push면 자동 배포.
두 플랫폼 모두 무료 티어를 활용할 수 있어서 비용 부담도 적었다.
(Strapi Cloud는 월 2만원 정도 나가지만, 그 편의성을 생각하면 납득이 됐다)
콘텐츠 변경 시 /api/revalidate로 특정 페이지만 즉시 갱신할 수 있는 것도
운영 관점에서 큰 편리함이었다.
돌이켜보며
이 프로젝트를 통해 가장 크게 배운 건 이런 것들이다.
- Headless CMS는 "콘텐츠 모델링"이 핵심이다. 관계형 데이터를 잘 설계하면 프론트엔드 개발이 훨씬 수월해진다.
- ISR + 태그 기반 캐시 무효화는 블로그에 최적이다. 정적 사이트의 속도와 동적 사이트의 유연성을 동시에 가져갈 수 있다.
- API 프록시 패턴은 보안과 유연성을 동시에 챙긴다. 백엔드 교체 시 프론트엔드 변경을 최소화할 수 있었다.
- 분석 도구는 처음부터 넣어야 한다. 나중에 붙이려면 귀찮고, 초기 데이터를 놓친다.
- 개인 프로젝트에서의 보안 습관이 실무로 이어진다. 대충 하고 싶은 유혹을 이기자.
- 프론트엔드 개발자도 백엔드를 경험해야 한다. 데이터 모델링, 인증, API 설계를 직접 해보면 협업할 때 시야가 달라진다.
결국 블로그를 만든다는 건, 단순히 글을 올릴 공간을 만드는 게 아니라
풀스택 개발의 모든 과정을 압축해서 경험하는 것이었다.
그리고 그 경험이 회사 업무에서도 분명히 힘을 발휘하고 있다고 느낀다.