우리는 지금까지 React를 사용하여 동적인 사용자 인터페이스를 만드는 방법에 집중해왔습니다.
기본적으로 React 애플리케이션은 사용자의 브라우저에서 JavaScript를 실행하여 화면을 그리는
클라이언트 사이드 렌더링(Client-Side Rendering, CSR)
방식으로 동작하는 경우가 많습니다.
CSR은 풍부한 상호작용을 제공하지만, 초기 로딩 시 사용자가 빈 화면을 보게 되거나 검색 엔진 최적화(SEO)에 어려움을 겪는 단점이 있을 수 있습니다.
이러한 단점을 보완하기 위해 등장한 것이 바로 *서버 사이드 렌더링(Server-Side Rendering, SSR)*과 *정적 사이트 생성(Static Site Generation, SSG)*입니다.
오늘은 이 다양한 렌더링 방식들이 각각 어떻게 동작하고 어떤 특징을 가지는지, 그리고 이들과 밀접하게 관련된
Hydration
이라는 개념은 무엇인지 자세히 알아보겠습니다.
🚀
CSR: Client-Side Rendering 🔗
먼저 우리가 가장 익숙한 방식인 클라이언트 사이드 렌더링(CSR)을 간단히 알아보겠습니다.
- 사용자가 웹사이트에 접속하면 브라우저는 최소한의 HTML 파일과 JavaScript 번들 파일을 다운로드합니다.
- 브라우저는 다운로드한 JavaScript를 실행합니다.
- JavaScript(React 코드)가 실행되면서 가상 DOM을 만들고, 실제 DOM을 조작하여 화면에 UI를 그립니다.
- 이후 사용자 상호작용에 따라 JavaScript가 계속해서 UI를 업데이트합니다.
- 첫 로딩 이후 페이지 이동 시 빠르고 부드러운 사용자 경험을 제공합니다 (페이지 전체 새로고침 없음).
- 서버 부하가 적습니다 (서버는 주로 API 역할만 수행).
- 다양한 동적 상호작용 구현에 유리합니다.
- 초기 로딩 시 JavaScript 번들 파일을 다운로드하고 실행하는 시간이 필요하여, 사용자가 첫 화면을 보기까지 시간이 걸릴 수 있습니다 (Time To First Meaningful Paint 느림).
- 초기 HTML이 거의 비어있어 검색 엔진 크롤러가 콘텐츠를 제대로 수집하기 어려울 수 있습니다 (SEO 문제).
🚀
SSR: Server-Side Rendering 🔗
서버 사이드 렌더링(SSR)은 CSR의 초기 로딩 및 SEO 단점을 해결하기 위해 등장한 방식입니다.
SSR은 이름 그대로, 웹 페이지 내용을
서버 측에서 미리 렌더링
하여 완성된 HTML 형태로 클라이언트(브라우저)에게 전달하는 방식입니다.
- 사용자가 웹사이트에 접속하면 브라우저는 서버에 페이지를 요청합니다.
- 서버는 요청받은 페이지에 필요한 데이터(API 호출 등)를 가져와서, React 컴포넌트를 렌더링하여 완전한 HTML 문자열을 생성합니다.
- 서버는 이 완성된 HTML을 브라우저에게 응답으로 보냅니다.
- 브라우저는 서버로부터 받은 HTML을 즉시 화면에 표시합니다 (사용자는 콘텐츠를 빠르게 볼 수 있음).
- 동시에 브라우저는 필요한 JavaScript 번들 파일을 백그라운드에서 다운로드합니다.
- JavaScript 로딩이 완료되면, React가 실행되어 서버에서 생성된 정적 HTML 위에 이벤트 핸들러 등을 연결하여 상호작용 가능한 상태로 만듭니다 (이 과정을
Hydration
이라고 합니다. 잠시 후 자세히 알아볼게요).

CSR과 SSR의 초기 로딩 과정을 비교
초기 로딩 속도 (TTFP/FCP)
TTFP(Time To First Paint)와 FCP(First Contentful Paint)는 사용자가 첫 화면을 보기까지 걸리는 시간을 측정하는 지표입니다.
SSR은 서버에서 완성된 HTML을 보내주므로 사용자가 첫 화면 콘텐츠를 보는 시점(First Contentful Paint, FCP)이 CSR보다 빠릅니다. 사용자가 느끼는 초기 로딩 성능이 좋습니다.
SEO
서버에서 완성된 HTML을 제공하므로 검색 엔진 크롤러가 페이지 콘텐츠를 쉽게 수집할 수 있어 SEO에 유리합니다.
서버 부하
각 사용자 요청마다 서버에서 페이지를 렌더링해야 하므로 CSR보다 서버 부하가 높습니다.
첫 바이트까지의 시간 (TTFB)
서버에서 HTML을 생성하는 시간이 필요하므로, 서버로부터 첫 번째 데이터 바이트를 받는 시간(Time To First Byte, TTFB)은 CSR보다 느릴 수 있습니다.
전통적인 SSR은 서버에서 페이지 전체 HTML 생성이 완료될 때까지 기다렸다가 응답을 보내므로, 페이지가 복잡하거나 데이터 로딩이 오래 걸리면 TTFB가 느려지는 단점이 있었습니다.
이를 개선하기 위해
스트리밍 SSR(Streaming SSR)
이라는 기술이 등장했습니다.
Next.js의 App Router (app 디렉터리 방식)는 기본적으로 스트리밍 SSR을 지원합니다.
스트리밍 SSR
서버는 페이지의 기본 골격(셸)을 먼저 보내고, 준비되는 대로 각 UI 조각(청크)들을 순차적으로 스트리밍하여 전송합니다.
브라우저는 도착하는 대로 HTML을 점진적으로 렌더링하고, 필요한 JavaScript도 함께 로드하여 Hydration을 수행합니다.
장점
사용자는 페이지의 일부라도 더 빨리 볼 수 있고, 서버 렌더링 시간이 전체 응답 시간을 막지 않아 TTFB 개선 및 사용자 경험 향상에 도움이 됩니다.
React Suspense와 긴밀하게 연동되어 동작합니다.
🚀
SSG (Static Site Generation) 🔗
정적 사이트 생성(SSG)은 웹사이트의 모든 페이지를
빌드 시점
에 미리 HTML 파일로 생성해두는 방식입니다.
- 개발자는 코드를 빌드(build)합니다.
- 빌드 과정에서 프레임워크(예: Next.js, Gatsby)는 정의된 모든 경로에 대해 페이지를 미리 렌더링하고, 각각을 별도의 HTML 파일로 생성합니다. (필요한 데이터도 빌드 시점에 가져옵니다)
- 생성된 HTML, CSS, JavaScript 파일들은 정적 파일 서버나 CDN(Content Delivery Network)에 배포됩니다.
- 사용자가 특정 페이지를 요청하면, 서버는 이미 만들어진 해당 HTML 파일을 즉시 사용자에게 전송합니다.
- CSR과 마찬가지로, 브라우저는 HTML을 표시한 후 JavaScript를 로드하여 페이지를 상호작용 가능하게 만듭니다 (Hydration).
✅
성능
미리 생성된 정적 파일을 제공하므로 요청 시 서버 렌더링 과정이 없어 매우 빠릅니다.
CDN을 활용하면 전 세계 어디서든 빠르게 콘텐츠를 전달할 수 있습니다.
서버 의존성/부하
서버는 단순히 정적 파일을 전달하는 역할만 하므로 서버 부하가 거의 없고, 서버 없이 운영하는 것도 가능합니다 (Jamstack 아키텍처).
보안
서버 측 로직이 거의 없으므로 공격 표면이 줄어들어 보안에 유리합니다.
빌드 시간
페이지 수가 많거나 데이터 로딩이 복잡하면 빌드 시간이 길어질 수 있습니다.
데이터 최신성
콘텐츠가 변경되면 사이트를 다시 빌드하고 배포해야 최신 내용이 반영됩니다.
(물론 Incremental Static Regeneration (ISR) 같은 기술로 이 단점을 보완하기도 합니다.)
SSG는 콘텐츠가 자주 변경되지 않고, 빌드 시점에 모든 페이지를 생성할 수 있는 경우에 매우 효과적입니다.
- 블로그 게시물
- 문서 사이트 (API 문서, 튜토리얼 등)
- 마케팅 페이지, 랜딩 페이지
- 포트폴리오 사이트
Q: "SSR과 SSG의 차이점은 무엇이고, 각각 언제 사용하는 것이 좋을까요?"
A: "SSR은 요청 시 서버에서 HTML을 생성하고, SSG는 빌드 시 HTML을 미리 생성합니다. SSR은 사용자별 동적 콘텐츠나 매우 자주 바뀌는 데이터에 적합하고, SSG는 정적 콘텐츠 위주의 사이트에서 최고의 성능을 제공합니다."
🚀
Hydration: 서버에서 생성된 HTML을 동적으로 만드는 과정 🔗
SSR이나 SSG로 생성된 HTML은 처음에는 그저 '보여주기만 하는' 정적인 문서입니다. 사용자가 버튼을 클릭하거나 입력하는 등의 상호작용을 하려면 JavaScript(React)가 필요합니다.
Hydration
은 서버에서 생성된 정적 HTML 위에 클라이언트 측 JavaScript(React)를 실행하여, 마치 물을 뿌려 마른 땅을 적시듯(hydrate) 상호작용이 가능한 동적인 애플리케이션 상태로 만드는 과정을 의미합니다.
Hydration 과정에서 React는 다음과 같은 중요한 작업들을 수행합니다.
이벤트 핸들러 부착
버튼 클릭(onClick
), 입력 변경(onChange
) 등 컴포넌트에 정의된 이벤트 핸들러들을 실제 DOM 요소에 연결합니다.
상태 초기화
useState
, useReducer
등으로 관리되는 컴포넌트의 내부 상태를 초기화하고, 필요하다면 서버에서 전달된 초기 상태 값을 사용합니다.
가상 DOM 트리 생성
서버에서 생성된 HTML 구조와 일치하는 가상 DOM 트리를 메모리에 생성하여, 이후 클라이언트 측에서의 업데이트를 효율적으로 처리할 준비를 합니다.
즉, Hydration은 서버가 만들어준 '뼈대(HTML)'에 React라는 '신경망과 근육(JavaScript)'을 연결하여 살아 움직이는 애플리케이션으로 완성하는 과정입니다.
Hydration 과정에서 React는 서버에서 렌더링된 HTML 구조와 클라이언트에서 렌더링하려는 가상 DOM 구조가
정확히 일치
할 것으로 기대합니다.
만약 두 구조 사이에 불일치가 발생하면, React는 Hydration을 제대로 수행할 수 없다는 경고(Hydration Mismatch Error)를 표시하고, 경우에 따라 클라이언트 측에서 전체를 다시 렌더링하게 되어 SSR/SSG의 이점을 잃을 수도 있습니다.
이런 불일치는 주로 다음과 같은 경우에 발생할 수 있습니다.
- 서버 환경과 클라이언트 환경 간의 차이 (예:
window
객체 접근, 타임존 차이 등)
- 잘못된 HTML 중첩 구조 (예:
p
태그 안에 div
넣기)
- 렌더링 시점에 따라 내용이 달라지는 로직 (예:
Math.random()
, 현재 시간 표시 - 서버 렌더링 시점과 클라이언트 Hydration 시점이 다름)
이런 오류를 피하려면 서버와 클라이언트에서 렌더링 결과가 일관되도록 코드를 작성하는 것이 중요합니다. 필요한 경우 useEffect
등을 사용하여 클라이언트에서만 실행되어야 하는 로직을 분리해야 합니다.
최근 프론트엔드 커뮤니티에서는 SSR/SSG의 장점을 살리면서도 JavaScript 로딩 및 실행 비용을 줄이기 위한 새로운 패턴들이 주목받고 있습니다.
✅
부분 Hydration (Partial Hydration) 🔗
페이지 전체를 한 번에 Hydration 하는 대신, 상호작용이 필요한
일부 컴포넌트만
선택적으로 Hydration 하는 방식입니다.
정적인 부분은 HTML로 남겨두고, 동적인 부분만 JavaScript를 로드하여 실행하므로 초기 로딩 및 상호작용까지의 시간(Time to Interactive, TTI)을 단축할 수 있습니다.
✅
아일랜드 아키텍처 (Islands Architecture) 🔗
부분 Hydration 개념을 기반으로, 웹 페이지를 정적인 HTML '바다' 위에 떠 있는 여러 개의 상호작용 가능한 '섬(Island)'들로 구성하는 아키텍처 패턴입니다.
각 '섬'은 독립적인 위젯 또는 컴포넌트이며, 자체적으로 스크립트를 로드하고 Hydration을 수행합니다.
각 컴포넌트(섬)가 필요한 JavaScript만 로드하므로 전체 JS 페이로드가 줄어듭니다.
중요하지 않은 컴포넌트의 JS 로딩이 다른 중요한 컴포넌트의 상호작용을 막지 않습니다.
점진적인 Hydration이 가능하여 TTI를 더욱 개선할 수 있습니다.
Astro, Fresh와 같은 최신 프레임워크들이 이 아키텍처를 적극적으로 채택하고 있으며, Next.js의 서버 컴포넌트도 유사한 목표를 가지고 있습니다.

아일랜드 아키텍처. 각 섬마다 독립적인 JS 로딩 및 Hydration 발생
오늘은 React 애플리케이션을 사용자에게 보여주는 다양한 렌더링 방식에 대해 깊이 알아보았습니다.
CSR
은 클라이언트에서 모든 것을 처리하며 풍부한 상호작용에 강점이 있지만, 초기 로딩과 SEO에 약점이 있을 수 있습니다.
SSR
은 서버에서 HTML을 미리 렌더링하여 초기 로딩 속도와 SEO를 개선하지만, 서버 부하가 증가할 수 있습니다. 스트리밍 SSR
은 TTFB를 개선하는 진화된 형태입니다.
SSG
는 빌드 시점에 정적 HTML을 생성하여 최고의 성능과 안정성을 제공하지만, 동적인 데이터 처리에는 제약이 따릅니다.
Hydration
은 SSR/SSG로 생성된 정적 HTML 위에 JavaScript(React)를 적용하여 상호작용 가능한 앱으로 만드는 필수 과정입니다.
부분 Hydration
과 아일랜드 아키텍처
는 필요한 부분만 JavaScript를 로드하고 실행하여 성능을 더욱 최적화하려는 최신 접근 방식입니다.
어떤 렌더링 방식이 절대적으로 좋다고 말하기는 어렵습니다. 애플리케이션의 특징, 콘텐츠의 동적성, 성능 요구사항, SEO 중요도 등을 종합적으로 고려하여 가장 적합한 방식을 선택하거나 혼합하여 사용하는 것이 중요합니다.
Next.js와 같은 프레임워크는 이러한 다양한 렌더링 전략을 편리하게 사용하고 조합할 수 있도록 많은 기능을 제공하고 있습니다.
다음 시간에는 React와 함께 사용되는 다양한
자료구조
에 대해 알아보겠습니다.
배열, 연결 리스트, 트리 등 기본 자료구조들이 React의 내부 동작이나 컴포넌트 구현에 어떻게 활용되는지 살펴보며 기본기를 더욱 탄탄히 다져보겠습니다.