한양과학기술고등학교

에듀테크 프로젝트 대시보드

SSR vs CSR vs SSG

같은 웹페이지도 HTML을 언제, 어디서 완성하는지에 따라 체감 속도와 서버 부하가 완전히 달라진다. 브라우저가 받은 HTML을 화면 픽셀로 바꾸는 과정(렌더링 파이프라인) 이전 단계 — 즉 "완성된 HTML을 누가 언제 만드는가"를 비교한다. 각 카드의 버튼을 눌러 요청 한 번의 타임라인을 시뮬레이션해보자.

CSR (Client-Side Rendering)
브라우저가 JS로 화면을 그린다 — React/Vue SPA 기본 모드
1서버: 거의 빈 HTML + JS 링크만 응답
2브라우저: JS 번들 다운로드·파싱·실행
3JS: API 서버에 데이터 fetch 요청
4데이터 도착 → DOM 그리기 → 이벤트 연결
TTFB
—
FCP
—
TTI
—
SSR (Server-Side Rendering)
요청마다 서버가 완성된 HTML을 생성 — 이 사이트(FastAPI+Jinja2)가 이 방식
1서버: DB 조회 + 템플릿에 데이터 삽입
2서버: 완성된 HTML 문자열 응답
3브라우저: 즉시 화면에 표시 (콘텐츠 보임)
4브라우저: JS 도착 후 하이드레이션(이벤트 연결)
TTFB
—
FCP
—
TTI
—
SSG (Static Site Generation)
빌드 시점에 미리 HTML 파일을 만들어 CDN에 배포
1(빌드 타임, 요청 전) 모든 페이지 HTML 미리 생성
2사용자 요청 → CDN이 파일을 그대로 응답 (서버 연산 없음)
3브라우저: 즉시 화면에 표시
4필요시 JS 하이드레이션 (인터랙션용)
TTFB
—
FCP
—
TTI
—
체감 속도 비교 (예시 수치, 데이터 크기·네트워크에 따라 변동)
기준 CSR SSR SSG
HTML 생성 시점 브라우저 (요청 후) 서버 (요청마다) 빌드 타임 (요청 전 미리)
서버 부하 낮음 (정적 파일만) 높음 (매 요청 렌더링) 거의 없음 (CDN이 처리)
SEO / 크롤러 불리 (빈 HTML로 보일 수 있음) 유리 (완성된 HTML) 가장 유리
데이터 신선도 항상 최신 (매번 fetch) 항상 최신 (매번 렌더링) 빌드 시점 기준 (ISR로 보완 가능)
개인화 데이터 (로그인 등) 적합 적합 부적합 (모두에게 같은 파일)
대표 예시 React SPA, 대시보드 FastAPI+Jinja2(이 사이트), Next.js SSR 블로그, 문서 사이트, GitHub Pages
코드로 보는 차이
// CSR: 브라우저에서 실행 async function load() { const res = await fetch("/api/posts"); const data = await res.json(); root.innerHTML = render(data); } load(); // 빈 화면 → 이후 채워짐
# SSR: FastAPI (이 사이트 방식) @app.get("/posts") async def posts(request: Request): data = await db.fetch_all() # 서버에서 완성된 HTML 반환 return templates.TemplateResponse( request, "posts.html", {"data": data})
// SSG: 빌드 스크립트 (한 번만 실행) for (const post of allPosts) { const html = renderToString(post); fs.writeFileSync( `dist/${post.slug}.html`, html); } // 이후 요청은 이 파일들을 그대로 서빙
이 사이트는 어디에 해당할까? offset0xf.com은 요청이 들어올 때마다 FastAPI가 Jinja2 템플릿에 데이터를 채워 완성된 HTML을 매번 새로 만들어 응답한다 — 즉 SSR이다. 다만 React 같은 프레임워크의 "하이드레이션"(서버 HTML 위에 JS로 이벤트를 재연결하는 과정) 없이, 페이지 이동마다 서버가 새 HTML을 통째로 내려주는 전통적인 멀티페이지(MPA) 방식 SSR이라는 점이 Next.js식 SSR과 다르다.