Static Site Generation
SSG(Static Site Generation)는 빌드 타임에 HTML 파일을 미리 생성해 두고, 요청이 들어올 때 서버에서 실시간으로 렌더링하는 대신 이미 만들어진 파일을 그대로 반환하는 렌더링 전략입니다. 완성된 HTML은 CDN에 올려 전 세계 엣지에서 서빙할 수 있고, JS 번들이 로드되면 클라이언트에서 Hydration이 일어나 이후 상호작용은 SPA처럼 동작합니다.
▶아키텍처 다이어그램
🔄 프로세스 다이어그램점선 애니메이션은 데이터 또는 요청의 흐름 방향을 나타냅니다
서버가 요청마다 HTML을 만들면 데이터베이스 쿼리, 템플릿 렌더링, 사용자 맞춤 처리가 매번 반복됩니다. 블로그 글이나 문서 페이지처럼 누가 요청해도 같은 내용이 나오는 페이지라면 이 반복은 불필요합니다. 그렇다고 클라이언트에서 JS로 콘텐츠를 그리는 SPA 방식으로 가면, 크롤러가 빈 HTML을 만나 SEO가 어려워지고 첫 페이지 로드까지 걸리는 시간도 늘어납니다. SSG는 이 두 문제를 동시에 해소하려는 접근입니다. 언제 렌더링할지를 요청 시점에서 빌드 시점으로 옮기는 것입니다.
초기 웹은 PHP, JSP 같은 서버 사이드 렌더링이 기본이었습니다. 2010년대 중반 이후 React, Vue 같은 JS 프레임워크가 대중화되면서 SPA가 유행했는데, SEO와 초기 로딩 속도 문제가 불거졌습니다. 그 대응으로 서버에서 React를 렌더링하는 SSR이 등장했지만 요청마다 서버 연산 비용이 따른다는 한계가 있었습니다. Gatsby, Jekyll, Hugo 같은 도구들이 빌드 타임 생성 방식을 다시 주목하면서, 이번에는 현대적인 컴포넌트 모델과 결합한 SSG가 정착했습니다. Next.js의 getStaticProps/generateStaticParams가 이 패턴을 프레임워크 수준으로 흡수하면서 SSG는 선택 가능한 렌더링 전략 중 하나로 자리 잡았습니다.
SSG는 배포 전 빌드 단계에서 모든 작업이 일어납니다. 먼저 빌드 도구가 getStaticPaths나 generateStaticParams 같은 함수를 실행해 어떤 URL의 페이지를 생성할지 목록을 만듭니다. 이어서 각 페이지의 데이터 페칭 함수가 CMS나 API를 호출해 필요한 데이터를 가져오고, 그 데이터와 컴포넌트를 결합해 완성된 HTML 파일을 출력합니다. 결과물은 순수한 HTML + CSS + JS 번들이고, 이 파일들을 CDN에 올리면 배포가 끝납니다. 브라우저가 HTML을 받아 그리고 나서 JS 번들이 로드되면 Hydration이 일어납니다. Hydration은 서버(빌드 시점)에서 만든 DOM에 이벤트 핸들러와 상태를 연결하는 과정으로, 이 단계가 끝나야 버튼 클릭 같은 인터랙션이 동작합니다.
SSG, SSR, SPA는 렌더링이 '언제' 일어나는지로 구분됩니다. SSG는 빌드 타임에 HTML을 생성합니다. 내용이 한번 만들어지면 요청마다 서버 연산이 없습니다. 콘텐츠가 자주 바뀌지 않는 페이지에서 성능과 CDN 배포 용이성이 가장 좋습니다. 다만 빌드 없이는 새 콘텐츠가 반영되지 않으므로, 실시간으로 데이터가 바뀌는 페이지에는 적합하지 않습니다. SSR은 요청 시점에 서버가 HTML을 생성합니다. 사용자마다 다른 데이터(로그인 상태, 권한 등)가 필요하거나 최신 데이터가 즉시 반영돼야 할 때 적합합니다. 대신 요청마다 서버 연산 비용이 발생합니다. SPA는 브라우저에서 JS가 HTML을 그립니다. 첫 응답은 거의 빈 HTML이고 JS 실행 후 화면이 채워집니다. 인터랙션이 많은 앱에 유리하지만 SEO와 초기 로딩 시간이 약점입니다. SSG에서도 Hydration은 일어납니다. 브라우저가 정적 HTML을 그린 뒤 JS 번들이 로드되면 컴포넌트 트리를 다시 실행해 이벤트와 상태를 연결합니다. SSG는 '서버 렌더링을 없앤 것'이 아니라 '빌드 타임으로 옮긴 것'입니다.
SSG가 가장 자연스러운 상황은 콘텐츠가 배포 단위로 바뀌는 경우입니다. 개발 블로그, 기술 문서, 제품 소개 페이지, 이벤트 랜딩 페이지처럼 편집 주기가 코드 배포와 크게 다르지 않은 서비스라면 SSG만으로 충분합니다. 빌드 타임에 생성된 HTML은 캐시 전략을 가장 단순하게 유지할 수 있습니다. 파일명에 콘텐츠 해시가 붙기 때문에 Cache-Control을 최대치로 설정해도 배포 시 URL이 바뀌어 자동으로 캐시가 갱신됩니다. 반면 사용자별 개인화 화면, 실시간 재고나 가격, 로그인 후 대시보드처럼 요청 시점의 데이터가 결과를 바꾸는 페이지는 SSG만으로는 처리할 수 없습니다. 이런 부분은 클라이언트에서 별도 API 호출로 처리하거나, SSR이나 서버 컴포넌트로 전환하는 방식을 함께 씁니다. 실제 서비스는 SSG와 다른 렌더링 전략을 페이지 단위로 혼합해서 사용하는 경우가 많습니다.