2022년 React 18 버전에서 정식으로 React Server Component(RSC) 가 도입이 되었다. 이 글에서 RSC이 왜 생겨났고, 어떤 것인지 한번 알아보자.
초기 웹 페이지는 서버에서 HTML을 만들어 전달해주는 방식으로 동작을 했다.
이후 Ajax라는 기술이 나오게 되면서 급격하게 발전하기 시작했다.
이때 사용자의 경험을 향상 시키기 위한 목적으로 Single Page Application (SPA)을 지원하는 도구들이 많이 생겨 났고, React 도 그러한 목적으로 등장했다.
CSR로 동작하는 React 는 페이지가 로드 되면 기존보다 훨씬 빠르고, 인터렉티브한 앱을 보여줄 수 있다는 큰 장점이 생겨났다.
기존 React는 기본적으로 클라이언트(사용자의 브라우저 환경)에서 동작 하도록 설계 되어있었다.
하지만, 자바스크립트 번들사이즈가 커지면서 나중에는 빠르게 동작하지만, 초기 로딩 속도, SEO 등에서 큰 단점을 보이게 된다. 자바스크립트가 로드 될 때 까지 “텅”빈 화면을 봐야한 다는 것이었다.

“이때 번들 사이즈를 줄이기 위해
React.lazy등Code Spliting,Suspense와 같은 기술이 생겼다.”
초기 로딩 속도가 느리다는 단점을 조금이나마 해소시키기 위해 Next.js, Remix 같은 프레임워크에서 SSR 방식이 함께 사용되기 시작했다. 이 덕분에 단점으로 지목되던 초기로딩속도와 SEO 에 개선을 많이 얻을 수 있게 되었다.
SSR을 통해 해결책을 마련하기는 했지만, 이 방식은 “페이지에 처음 접근 할 때만 유의미하게 사용되었고”, 결국에는 Hydration 과정을 통해 다시 이후에는 CSR로 작동하게 된다.
Hydration ❓
“서버에서 렌더링된 정적인 HTML에 React가 클라이언트에서 상호작용 할 수 있도록 자바스크립트 파일을 다운로드 하는 과정”

[출처] 한입 크기로 베워먹는 Next.js
즉, SSR은 빠르게 초기 페이지에 접속할 수 있다는 이점을 가져오지만, 결국에는 인터렉테브한 동작을 위해 다시 CSR로 동작하기 때문에 기존의 React의 단점은 그대로 가져가게 된다.
위 문제를 해결하기 위해 Streaming SSR을 도입하기도 하였다. 덕분에 사용자는 Hydration 과정이 끝나기 전에 상호작용이 가능해졌다.
Streaming SSR ❓
“React 18에서 등장한 Concurrent mode처럼 Hydration 작업을 여러 작은 단위의 Hydration으로 나눠 우선순위에 따라 Hydration을 진행합니다”
하지만, 여전히 *Hydration을 위한 자바스크립트 번들을 다운 받아야 하는 과정은 사라지지 못했다.*
SSR 렌더링 과정의 단점
- 화면에 보여주길 원하는 모든 것은 “서버”에서 Fetching 되어야 한다.
- 자바스크립트 번들이 모두 다운로드 되기전까지는 Hydration이 진행되지 않는다.
- Hydration이 끝나기 전까지는, 사용자와 상호작용할 수 없다.
기존 React에서는 모든 데이터 Fetching을 브라우저에서 직접 호출해서 가져왔어야 했기 때문에 API 호출 지연으로 인한 waterfall 현상이 발생하였다.
이로 인해 UI 렌더링이 단계적으로 이루어져 사용자 경험에 지연을 초래할 수 있었다.
waterfall ❓
“여러 비동기 데이터 요청이나 네트워크 호출이 순차적으로 발생하면서, 이전 요청이 완료된 후에야 다음 요청이 시작되는 현상”
더불어 의견이 분분하지만, 브라우저에서 API를 통해 데이터를 주고 받는 과정에서 노출이 일어나기 때문에 보안상 해결책이 필요하다는 목소리도 있었다.
문제
- 불필요하게 큰 자바스크립트 번들 사이즈 → 빠른 인터렉션 불가
- 컴포넌트에서의 잦은 서버 API 요청으로 waterfall 현상 발생
그래서 React 팀은 위의 문제들을 해결하기 위해 고민을 했고, “서버 컴포넌트”라는 개념을 제시하게 된다.
React Server Component 는 말 그대로 “서버에서 실행되는 React 컴포넌트”를 의미한다.
“서버에서만 실행되는 React 컴포넌트”

다시 말하면 “서버의 컴포넌트화” 라고 할 수 있다. 기존의 서버에서 하던 작업들을 “페이지 단위”가 아니라 각각의 컴포넌트 단위에서 할 수 있다는 말이 된다.
클라이어튼 컴포넌트와 서버 컴포넌트가 나눠져 있고, 이것들이 하나의 컴포넌트 트리로 동작하도록 제시한 개념이다.
서버 컴포넌트는 “서버에서 동작하고 렌더링 된다는 특성” 을 가지면서 덕분에 여러 특징을 가져올 수 게 되었다.
서버는 “렌더링 결과” 만 전달하게 되면서 “컴포넌트 전체”를 브라우저에 넘겨주어야 했다면, 이것을 하지 않게 되어 번들 사이즈를 줄일 수 있게 하였다.
또한 렌더링된 결과는 “점진적으로” Streaming 으로 전달하여, 브라우저와 서버에서 렌더링을 진행하는 동안에서도 State 유지가 가능하도록 하였다.
서버 컴포넌트(RSC)가 실행되어 렌더링 되어 사용자의 화면에 보여지게 되는 단계는 크게는 다음과 같다.
RSC Payload 생성RSC Payload와 HTML을 응답한다.RSC Payload를 기반으로 Virtual DOM을 생성하고, 브라우저 DOM에 반영한다.RSC Payload
- 서버에서 RSC를 실행해 만든 결과물
보유 내용
- React Element를 직렬화 한 결과물 (JSON 과 비슷한 형식)
- 클라이언트 컴포넌트가 위치할 주소 (경계 라고함)
- RSC 가 RCC 에 전달하는 props

서버 컴포넌트는 서버에서 동작하기 때문에 데이터베이스, 파일 시스템 같은 백엔드 리소스에 직접 접근 할 수 있다.
// Note.server.js - 서버 컴포넌트
import fs from 'react-fs';
import db from 'db.server';
function Note(props) {
const note = db.notes.get(props.id); // 데이터베이스 접근
const noteFromFile = JSON.parse(fs.readFile(`${id}.json`)); // 파일 접근
if (note == null) {
// handle missing note
}
return (/* render note here... */);
}
서버 컴포넌트는 위에서 간단하게 본 내용대로 브라우저에서 다운로드 되지 않고, 서버에서 실행된 결과를 가져오기 때문에, 번들 사이즈에는 전혀 영향을 주지 않는다.
번들 사이즈에 영향을 주는 부분은 오로지 기존의 클라이언트 컴포넌트의 담당이 되는 것이다.
이를 이용하여 유저 인터렉션이 없는 컴포넌트는 서버 컴포넌트로 만들어 버리면, 번들 사이즈를 줄이는데 도움이 될 것이다.
Code Splitting은 번들 사이즈를 줄이기 위해서 여러 개의 작은 번들로 쪼개는 기술을 의미한다.
기존에 클라이언트 컴포넌트에서는 React.lazy와 Dynamic Import 를 사용하여 Code Splitting 이 자동으로 일어나도록 구현하였다.
이것을 적용하기 위해서는 다음과 같은 불편함이 있었다.
React.lazy와 dynamic import 를 적용해야 함서버 컴포넌트는 Import 되는 모든 클라이언트를 Code Splitting 포인트로 간주하기 때문에, 더 이상 따로 명시해줄 필요가 없어졌다.
또한 서버에서 미리 필요한 컴포넌트를 선택하기 때문에 클라이언트는 렌더링 프로세스 초기에 번들을 다운로드 할 수 있다.
클라이언트 컴포넌트(RCC)와 서버 컴포넌트(RSC) 를 간단하게 표로 비교해보자.
| 클라이언트 컴포넌트(RCC) | 서버 컴포넌트(RSC) | |
|---|---|---|
| 실행 위치 | 브라우저 | 서버 |
| Hydration 여부 | ⭕ | ❌ |
| 브라우저 API | ⭕ | ❌ |
| React API | ⭕ | ❌ |
| 서버 리소스(DB, 파일 시스템 등) | ❌ | ⭕ |
| 주요 목적 | 사용자 인터렉션, 동적 상태 관리, 애니메이션, 브라우저 API 사용 | 무거운 데이터 Fetching, 보안에 필요한 연산( 비밀 API 키 사용) , 초기 렌더링 성능 최적화 |
| 사용 방법 | “use client” 선언 필요 | Next.Js 15 기준 필요 없음 |
필자도 서버 컴포넌트에 대해서 제대로 공부하기 전에는 다름을 인식하지 못했다.
하지만, 지금에서 분명하게 이야기 할 수 있는 것은 SSR과 RSC는 완전히 다른 개념이라는 것이다.
서버 사이드 렌더링(SSR)은 단순히 “초기로딩속도(FCP)”를 개선하기 위해서 서버에서 HTML을 미리 그려서 보내주는 개념이다.
그렇기 때문에 서버 컴포넌트가 등장하기 이전에서도 어렵지 않게 SSR을 통해 최적화가 가능할 수 있엇다.
서버 컴포넌트(RSC)는 “서버에서 실행되는 컴포넌트” 이기 때문에 실행 결과로 RSC Payload를 반환한다.
둘다 서버에서 동작한다는 공통점이 있었기 때문에 다름을 인식하지 못하고 혼동했을 가능성이 높다고 생각한다. 하지만 둘은 사용 목적과, 범위 자체가 다르기 때문에 다른 개념임을 반드시 기억하자.
그렇기 때문에 Next.js 15버전 App Rotuer에서는 기본적으로 모든 컴포넌트를 “서버 컴포넌트”로 동작하도록 설계하고, 이를 서버에서 렌더링함으로 SSR + RSC를 동시에 활용하는 구조로 제공을 한다.
그렇기 때문에 Next.js는 기존 React의 단점인 “초기로딩속도”를 보완하는 동시에 서버컴포넌트를 통해 JS 번들 사이즈도 줄이는 방안으로 최적화 하도록 하여 제공한다.
“클라이언트 컴포넌트" -> "서버 컴포넌트" Import ❌
-> 무시할 경우, 서버 컴포넌트가 클라이언트 번들에 포함되고 클라이언트에서 렌더링
“서버 컴포넌트" -> "서버 컴포넌트", "클라이언트 컴포넌트" Import 가능
ServerComponents.dev | What are RSCs
React Server Component 이모저모 알아보기
Introducing Zero-Bundle-Size React Server Components – React
How React server components work: an in-depth guide
React 18: 리액트 서버 컴포넌트 준비하기 | 카카오페이 기술 블로그