개발 slecs

정적 빌드에서 런타임 DB 조회로 콘텐츠 아키텍처 전환

목차

빌드타임에 묶여 있던 콘텐츠 레이어를 런타임 DB 조회로 전환했다. 영향 범위가 핵심 페이지 전체라 결정 자체보다 "어떻게 안전하게 넘어가느냐"가 더 큰 숙제였던 작업이다.


왜 전환이 필요했나

기존 구조는 Astro의 Content Collection을 활용한 전형적인 정적 사이트 패턴이었다. 마크다운 파일을 소스로 삼고, 빌드 시점에 슬러그를 수집해서 getStaticPaths로 페이지를 찍어내는 방식. 작은 규모일 때는 이게 꽤 깔끔하다. 파일 시스템이 곧 CMS가 되고, 배포 파이프라인만 잘 잡으면 별도 서버 없이 굴러간다.

문제는 콘텐츠 관리 주체가 바뀌는 순간부터 발생한다. 운영자가 admin_db를 통해 직접 데이터를 다루기 시작하면, 파일 기반 컬렉션과 DB 사이에 이중 진실의 공급원(source of truth)이 생긴다. 이 상태를 방치하면 "파일엔 있는데 DB엔 없다" 혹은 그 반대 케이스가 조용히 쌓인다. 팀 입장에서 이 불일치는 버그보다 더 나쁜데, 버그는 터지면 알 수 있지만 불일치는 언제 터질지 모른다.

런타임 조회로의 전환은 사실 "기능 추가"라기보다 진실의 공급원을 하나로 통일하는 정리 작업에 가깝다.


변경된 파일들이 각각 의미하는 것

파일 기존 역할 전환 후 역할
[...slug].astro Content Collection에서 슬러그 수집 → 정적 경로 생성 admin_db에서 슬러그 조회 → 런타임 렌더링
c/[category].astro 빌드 시 카테고리 목록 고정 DB 카테고리 기준으로 동적 응답
index.astro 빌드 시점 최신 글 목록 고정 요청 시점 최신 글 목록 반영
rss.xml.js 빌드 결과물로 RSS 생성 런타임 DB 기준 RSS 생성
sitemap-index.xml.ts 정적 빌드 결과 기반 사이트맵 DB 항목 기반 동적 사이트맵

RSS와 사이트맵까지 함께 건드린 게 포인트다. 콘텐츠 페이지만 전환하고 사이트맵/RSS를 빌드타임 결과물로 남겨두면 검색엔진이나 피드 구독자 입장에서 불일치가 발생한다. DB에 새 글이 들어와도 사이트맵엔 반영이 안 되는 상황. 이 부분까지 같이 묶어서 처리한 건 맞는 판단이었다.


전환 과정에서 신경 쓴 부분

Astro에서 Content Collection → 런타임 조회 전환은 getStaticPaths 제거와 직결된다. 정적 경로 수집 로직을 걷어내고, 대신 서버사이드에서 슬러그를 받아 DB를 직접 쿼리하는 흐름으로 바꾼다.

// before: 빌드타임 경로 수집
export async function getStaticPaths() {
  const entries = await getCollection('posts');
  return entries.map(entry => ({
    params: { slug: entry.slug },
    props: { entry },
  }));
}

// after: 런타임 DB 조회
const { slug } = Astro.params;
const post = await getPostBySlug(slug); // admin_db 조회
if (!post) return Astro.redirect('/404');

겉보기엔 단순한 코드 교체지만, 영향이 퍼지는 범위가 넓다. output: 'static'이었다면 output: 'server' (혹은 hybrid) 로 전환이 수반되고, 이는 호스팅/배포 방식 전체에 영향을 준다. 팀에 이 컨텍스트를 제대로 전달하는 게 코드 짜는 것만큼 중요한 이유가 여기 있다.


트레이드오프와 팀에 전달한 것

이 전환이 공짜는 아니다. 명확하게 포기하는 것들이 있다.

  • CDN 엣지 캐싱 단순성 감소: 정적 파일은 CDN에서 바로 서빙되지만, 런타임 조회는 캐싱 전략을 별도로 설계해야 한다
  • 빌드 결과물의 예측 가능성 감소: 빌드 로그만 봐도 "몇 개 페이지가 생성됐다"는 확신이 사라진다
  • 서버 의존성 증가: DB 응답이 느리거나 장애가 나면 페이지 자체가 느려지거나 죽는다

반대로 얻는 것:

  • 콘텐츠 변경이 즉시 반영됨 (재빌드 불필요)
  • admin_db가 유일한 진실의 공급원으로 통일됨
  • 운영자가 배포 없이 콘텐츠를 다룰 수 있음

팀원들한테 코드리뷰 때 이 트레이드오프를 테이블에 올려놓고 같이 확인했다. "이렇게 하면 어떤 리스크가 생기는지"를 공유하지 않으면, 나중에 장애가 났을 때 "왜 이렇게 바꿨죠?"가 나오고 그게 팀 신뢰를 깎는다.


사이트맵, RSS, 슬러그 라우팅, 카테고리 페이지, 인덱스까지 한 번에 건드린 건 범위가 크긴 했다. 그래도 진실의 공급원 분리 문제는 "다음에 조금씩" 해결하는 게 더 비싸다. 한 번에 끊는 게 맞았다.

다음

댓글 0

첫 댓글 달아줘.