React Server Components(RSC)는 서버에서 렌더링되어 클라이언트로 전송되는 React 컴포넌트입니다. 기존의 클라이언트 컴포넌트와 달리 서버에서만 실행되므로, 데이터베이스나 파일 시스템에 직접 접근할 수 있으며 번들 크기에 전혀 영향을 주지 않습니다.
Server Component와 Client Component의 가장 핵심적인 차이는 실행 환경입니다.
| 항목 | Server Component | Client Component |
|---|---|---|
| 실행 환경 | 서버 | 브라우저 |
| 번들 포함 | 아니요 | 예 |
| DB/파일 직접 접근 | 가능 | 불가 |
| useState / useEffect | 사용 불가 | 사용 가능 |
| 이벤트 핸들러 | 사용 불가 | 사용 가능 |
| 브라우저 API | 사용 불가 | 사용 가능 |
Client Component는 파일 상단에 "use client" 지시어를 명시하여 선언합니다. 지시어가 없는 컴포넌트는 기본적으로 Server Component로 취급됩니다.
// ServerComponent.jsx — 지시어 없음, 서버에서 실행
async function ProductList() {
const products = await db.query("SELECT * FROM products");
return <ul>{products.map(p => <li key={p.id}>{p.name}</li>)}</ul>;
}
// ClientComponent.jsx
"use client";
function LikeButton({ productId }) {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(!liked)}>{liked ? "♥" : "♡"}</button>;
}
Server Component는 Client Component를 자식으로 포함할 수 있습니다. 반대로 Client Component 내부에서 Server Component를 import하여 직접 렌더링하는 것은 허용되지 않습니다. 다만 children props로 전달받는 방식은 가능합니다.
RSC는 Suspense와 결합하여 스트리밍(Streaming)을 지원합니다. 모든 컴포넌트의 렌더링이 완료될 때까지 기다리지 않고, 준비된 부분부터 순차적으로 클라이언트에 전송합니다.
서버 클라이언트
│ │
├─ Shell(레이아웃, 헤더) 전송 ──────▶│ 즉시 표시
│ │
├─ 데이터 로딩 중... │ Suspense fallback 표시
│ │
└─ ProductList 완성 후 전송 ────────▶│ 실제 콘텐츠로 교체
스트리밍(Streaming): 응답 데이터를 한 번에 보내지 않고 준비된 조각부터 순차적으로 전송하는 방식.
첫째, 번들 크기를 줄일 수 있습니다. Server Component에서 사용하는 라이브러리는 클라이언트 번들에 포함되지 않습니다. 예를 들어 마크다운 파싱 라이브러리를 Server Component에서만 사용한다면, 수백 KB의 코드가 브라우저로 전달되지 않습니다.
둘째, 데이터 접근이 간단해집니다. API 레이어를 거치지 않고 데이터베이스, 파일 시스템, 내부 서비스에 직접 접근할 수 있습니다.
셋째, 초기 페이지 로드 성능이 개선됩니다. 데이터를 서버에서 fetch하여 완성된 HTML을 전달하므로, 클라이언트에서 별도의 데이터 요청을 기다릴 필요가 없습니다.
Server Component에서는 React의 상태(state)와 생명주기(lifecycle)를 사용할 수 없습니다. useState, useEffect, useContext, useReducer 같은 훅이 모두 금지됩니다. 브라우저 이벤트 핸들러(onClick, onChange 등)도 사용할 수 없습니다.
인터랙션이 필요한 부분은 Client Component로 분리하고, Server Component는 데이터 페칭과 정적 렌더링에 집중하는 방식으로 두 컴포넌트 유형을 조합하는 것이 RSC를 효과적으로 활용하는 기본 패턴입니다.
RSC는 현재 Next.js App Router에서 안정적으로 지원되며, React 팀에서 공식적으로 권장하는 데이터 페칭 방식으로 자리잡고 있습니다.