저번 포스팅에서 브라우저 렌더링을 다루어 보았었다.
오늘 이야기할 웹 렌더링은 유저가 보는 화면(HTML)을 어느 시점에, 어디서 만들 것인지를 고려하여 형태를 만들기 위해 취하는 전략이고
이렇게 선택된 전략으로 만들어진 HTML/CSS/JS 파일을 브라우저가 받은 이후 실제 화면으로 그려내는 과정이 브라우저 렌더링 이라고 보면 될 것 같다!
CSR
Client Side Rendering
클라이언트(브라우저)에서 콘텐츠를 렌더링 하는 방식
React는 기본적으로 CSR로 동작한다
→ 브라우저는 처음에 텅 빈 HTML을 받고 거대한 자바스크립트 파일(bundle.js)을 다운로드 및 실행한 뒤에야 화면을 그림
✔️ 동작방식

- 사용자가 웹사이트에 요청을 보냄
- 서버는 최소한의 HTML 파일과 JavaScript 파일을 클라이언트로 전송
- 브라우저는 JavaScript를 다운로드하고 실행하여 동적으로 페이지 콘텐츠 생성
- 이후 화면 갱신에 필요한 데이터는 API를 통해 서버로부터 비동기적으로 가져옴
✔️ 장점
- 빠른 페이지 전환과 부드러운 사용자 경험: 페이지가 처음 로드된 후에는 새로고침 없이 필요한 데이터만 받아와서 화면의 일부분만 동적으로 바꾸므로 전환이 빠르고 부드러움
- 서버 부하 감소: 서버는 정적 파일만 툭 던져주면 되고 잦은 요청 및 렌더링을 할 필요가 없어 서버 부담이 적음
✔️ 단점
- 느린 초기 로드 속도: 거대한 자바스크립트 번들 파일을 완전히 다운로드하고 실행하기 전까지는 유저에게 텅 빈 화면만 보이기 때문에 전체 페이지를 보기 전에 약간의 지연을 느낄 수 있음
- SEO 취약: 검색 엔진 입장에서 아직 콘텐츠가 완성되지 않은 초기 상태만 보기 때문에 페이지 내용을 제대로 수집하지 못함
(+) 최근 검색엔진은 자바스크립트를 실행하여 기다리는 과정을 거쳐 SEO에 걸릴 수 있도록 지원하기도 한다네요
✔️ CSR에 적합한 사용 예시
- 검색 엔진 노출(SEO)이 필요 없고 유저와의 상호작용이 많은 경우
예) 사용자 대시보드, 관리자 페이지 등
SSR
Server Side Rendering
서버에서 화면을 렌더링 하는 방식
→ 요청이 들어올 때마다 서버에서 최신 데이터를 반영한 HTML 파일을 실시간으로 완성하여 전달 (매 요청마다 서버에서 페이지를 새롭게 렌더링하여 전달)
✔️ 동작방식

- 사용자가 웹사이트에 요청을 보냄
- 서버가 요청을 받아 필요한 데이터를 DB또는 API에서 가져옴 (서버 측 데이터 페칭 완료)
- 서버에서 가져온 데이터를 기반으로 HTML을 완성한 뒤 브라우저에 전송
- 브라우저는 전달받은 HTML을 화면에 보여줌
- 이후 뒤따라 다운로드 받은 JavaScript 파일을 HTML에 결합하여 인터랙션이 가능하도록 만든다 (Hydration)
✔️ 장점
- 빠른 초기 화면 로드: 사용자가 진입했을 때 자바스크립트 로드를 기다리지 않고 서버가 이미 완성된 HTML을 내려주기 때문에 첫 화면이 빠르게 뜬다
- SEO에 유리: 검색 엔진이 사이트를 수집할 때 이미 내용이 다 채워져 있는 HTML을 읽기 때문에 검색 노출도가 높음
✔️ 단점
- 서버 부하 증가: 사용자가 요청할 때마다 서버가 매번 HTML을 렌더링하기 때문에 비교적 느리고 너무 많은 요청이 몰릴 경우 서버 과부하 가능성
- 사용자 경험 다소 저하: 화면은 일찍 뜨지만, 자바스크립트 로드 전에는 HTML 요소로만 있기 때문에, 버튼을 눌러도 이벤트가 반응하지 않을 수도 있고 페이지 이동 시마다 전체 화면을 서버에서 다시 받아와야 하므로 화면 깜빡임이 생길 수도 있다
(단, Next.js 같은 최신 프레임워크는 최초 진입만 SSR로 하고 이후 페이지 이동은 CSR 방식으로 하여 이 단점을 극복)
✔️ SSR에 적합한 사용 예시
- 최신 데이터의 실시간 유지가 중요한 페이지
예) 콘서트 티켓팅 페이지
- 검색엔진에 자주 노출되어야 하면서 최신성이 중요한 페이지
예) 이커머스(쇼핑몰), 뉴스 사이트, 트렌드 피드 등
SSG
Static Site Generation
빌드 타임(Build Time)에 미리 페이지를 사전 렌더링하는 방식
Next.js는 특별한 렌더링 설정이 없다면 기본적으로 SSG로 동작
✔️ 동작방식

- 웹사이트를 빌드(
npm run build)할 때 데이터를 미리 페칭
- 페칭한 데이터를 기반으로 정적 HTML 파일을 사전에 생성
- 생성된 HTML 파일들을 서버나 저장소에 올려두고 배포
- 사용자가 해당 페이지를 요청하면 이미 만들어진 HTML 파일을 그대로 복사하여 바로 보여줌
✔️ 장점
- 매우 빠른 응답 속도: 이미 만들어진 페이지를 보여주기 때문에 사용자 요청에 매우 빠른 속도로 응답 가능
- SEO에 유리: 검색 엔진이 사이트를 수집할 때 이미 만들어져 있는 HTML을 보기 때문에 아주 쉽고 빠르게 내용 수집
- 서버 비용 절감: 서버로 요청이 많이 몰려도 실시간 렌더링을 하지는 않으므로 서버 과부화 위험이 거의 없음
✔️ 단점
- 최신 데이터 반영 어려움: 빌드 하는 순간에 페이지를 딱 한번만 생성하기 때문에 DB 상 내용이 바뀌어도 과거 빌드 시점의 매번 똑같은 페이지만 응답한다
- 사용자 별 정보 제공 어려움: 유저마다 다른 정보를 보여줘야 하는 마이 페이지 같은 곳에는 적합하지 않다
(예: 사용자가 1,000명이라면 그만큼의 마이 페이지 정적 HTML 파일을 미리 렌더링 해놔야 하며, 또 확장도 어려움)
- 수정 시 재빌드 필요: 콘텐츠가 변경될 때마다 전체 사이트를 다시 빌드하여 배포해야함
- 빌드 지연 가능성: 수많은 데이터 및 페이지가 있는 경우 사전 렌더링이 오래 걸릴 가능성
✔️ SSG에 적합한 사용 예시
- 정보가 거의 변하지 않고 빠른 로딩과 SEO를 보장해야 하는 페이지
예) 회사 소개, 이용약관, 기술 블로그 등
ISR
Incremental Static Regeneration (증분 정적 재생성)
SSG 방식으로 생성된 정적 페이지를 설정한 일정 시간 주기마다 다시 생성하는 방식
→ SSG의 매우 빠른 속도라는 장점을 그대로 유지하면서, 전체 사이트를 다시 빌드하지 않고도 특정 페이지들만 주기적으로 최신 데이터로 업데이트(재생성)한다
✔️ 동작방식

- 웹사이트를 빌드할 때 데이터를 미리 페칭하여 이를 기반으로 정적 HTML 파일을 사전에 생성
- 이 때 정적 페이지의 유효 기간을 설정
- 설정한 유효 기간 전에 사용자가 페이지를 요청하면 기존에 있는 페이지를 즉시 보여준다
- 설정한 유효 기간이 지난 후 사용자가 페이지를 요청하면 일단 기존에 있는 페이지를 보여주고 뒤에서 새 데이터를 반영한 HTML을 준비
- 새 HTML 생성이 완료되면 정적 파일이 교체 되어 이후 들어오는 사용자부터는 최신 버전의 페이지를 보게 된다
✔️ 장점
- SSG처럼 빠른 속도 유지: 이미 만들어진 정적 파일을 우선 제공하므로 속도가 빠르면서도 어느 정도 최신 정보를 유연하게 제공할수 있다
- 전체 재빌드 불필요: 변경된 페이지만 다시 만들면 되므로 전체 사이트를 다시 빌드할 필요 없음
✔️ 단점
- 실시간으로 바로바로 정보가 반영되지는 못함: 유효 기간 사이의 데이터 변경 사항은 즉각 반영되지 않음
✔️ ISR에 적합한 사용 예시
- 사용량은 많으나 콘텐츠가 가끔 업데이트되는 경우
예) 인기 블로그 글 목록, 랭킹 차트
Next.jS에서 구현 방식
참고로 App Router 기준
- CSR: 컴포넌트 파일 최상단에
"use client" 라고 지시어 선언
- SSR: fetch 요청 시 옵션에
cache: 'no-store' 설정
- SSG: fetch 요청 시 옵션에
cache: 'force-cache' 설정
→ Next.js의 기본 동작 방식
- ISR: fetch 요청 시 옵션에
next: { revalidate: n } 설정
→ n은 초 단위(Seconds)
추가개념
🔍SEO
Search Engine Optimization
검색 엔진 최적화
-
네이버, 구글 같은 검색 엔진 크롤러가 내 서비스나 제품 등을 쉽게 이해하고 수집할 수 있도록, 검색 엔진에 효율적으로 노출되도록, 웹 페이지의 구조와 콘텐츠를 개선하는 과정을 일컫는 작업
-
정보 수집 대상은 주로 자바스크립트가 실행되기 전의 HTML에 작성된 내용
HTML 내부의 제목 태그, 메타 태그(Meta Tag), 오픈 그래프(OG) 등이 주 수집 대상
import type { Metadata } from "next";
export const metadata: Metadata = {
title: "ppnyoong의 velog",
description: "안녕하세요 기술블로그를 운영중인 ppnyoong입니다요",
};

💧Hydration
하이드레이션
- 서버에서 미리 렌더링된 정적인 HTML 구조 위에,브라우저가 뒤따라온 JavaScript 번들 파일을 다운로드하여 이벤트 핸들러(클릭, 스크롤 등)와 React 상태(State)를 결합하는 과정
→ 서버에서 렌더링 이후 브라우저가 JavaScript 번들을 다운로드하여 이미 있는 HTML과 연결하는 과정을 거치게 되는데, 이 과정을 Hydration이라고 한다
이 과정이 끝나야 이벤트 핸들러 등록, 상태 업데이트 등의 인터렉션이 가능해진다
- Hydration Mismatch
서버가 만들어준 HTML 구조와 클라이언트 자바스크립트를 읽어서 다시 맞추려는 구조가 서로 다를 때(예: 서로 실시간 시간이 맞지 않는 경우) 에러가 발생하게 되는데 이를 Hydration Mismatch라고 부른다
- 대표적인 원인
- 브라우저 전용 API 사용
서버 렌더링 시에는 존재하지 않기 때문에 불일치 발생 가능
- 랜덤 값 / 현재 시간에 의존하는 렌더링
서버렌더링과 클라이언트 렌더링 결과가 거의 항상 다르게 나옴
- 조건부 렌더링이 클라이언트에서만 다른 경우
- 해결 방법
- 브라우저 전용 로직은 클라이언트 컴포넌트 안에서만 사용
- 서버/클라이언트 렌더 결과를 같게 유지
초기 렌더에서는 서로 동일한 값을 사용하도록 하고
값 차이는 useEffect 이후(클라이언트 마운트 완료 후)에 안전하게 반영하기
- 클라이언트에서만 동작해야 하는 라이브러리는 동적 임포트(dynamic import)를 사용하면서
{ ssr: false } 옵션을 주어 서버 렌더링 대상에서 제외
정리
| 비교 항목 | CSR | SSR | SSG | ISR |
|---|
| 렌더링 주체 | 클라이언트 (브라우저) | 서버 (요청 시) | 서버 (빌드) | 서버(빌드+서버) |
| HTML 생성 시점 | 런타임 (유저 브라우저 내부) | 런타임 (유저가 요청한 바로 그 순간) | 빌드 타임 (npm run build 시점) | 빌드 타임 + 설정한 주기마다 백그라운드 재생성 |
| 초기 로딩 속도 | 느림 (JS 다운로드 대기 필요) | 빠름 (완성된 HTML 즉시 수령) | 빠름 | 빠름 |
| 데이터 최신성 | 실시간 | 요청 시점 실시간 | 과거 데이터 (빌드 시점) | 어느 정도 최신 유지 (설정한 주기마다) |
| SEO 최적화 | 불리 | 유리 | 유리 | 유리 |
| 서버 부하 / 비용 | 낮음 (정적 파일만 단순 서빙) | 높음 (매 요청마다 HTML 렌더링) | 낮음 (서버 렌더링 X) | 낮음 (설정한 주기마다만 렌더링) |
| Next.js 구현 옵션 | "use client" 지시어 사용 | { cache: 'no-store' } | { cache: 'force-cache' } (기본값) | { next: { revalidate: n } } (n은 초 단위) |
| 추천 사용 예시 | 대시보드, 마이페이지, 개인 사내 어드민 | 주식 차트, 콘서트 티켓팅, 실시간 금융 피드 | 회사 소개, 이용약관, 정적 기술 블로그 | 쇼핑몰 상품 상세 페이지, 인기 게시글 목록 |
참고
웹 렌더링과 CSR/SSR/SSG/ISR 정리 종결
[Next.js] CSR, SSR, ISR, SSG, 하이브리드(Hybrid) 렌더링, 하이드레이션(Hydration)
[React] CSR, SSR, SSG, ISR 이란?
SSR CSR SSG ISR 이해하기
[Next.js] App Router의 렌더링 전략 | CSR, SSR, SSG, ISR
[Next.js] Hydration이란?