React Server Components는 서버에서만 실행되는 컴포넌트입니다. JavaScript 번들에 포함되지 않아 클라이언트 번들 크기가 줄고, DB나 파일 시스템에 직접 접근할 수 있습니다.
React Server Components 실전 가이드
React Server Components의 개념, 사용 패턴, 클라이언트 컴포넌트와의 조합 전략을 정리한다. 'use client' 경계 설정, 데이터 페칭 패턴, 번들 크기 최적화와 실전 아키텍처 예시를 포함한다.
한 줄 요약: React Server Components(RSC)는 서버에서 렌더링되어 클라이언트 번들에 포함되지 않는 컴포넌트로, 번들 크기 감소와 데이터 페칭 간소화가 핵심 장점이다.
RSC는 React 18에서 도입되고 Next.js App Router에서 기본값이 된 패러다임이다. 기존 클라이언트 컴포넌트와 어떻게 다르고, 실전에서 어떻게 사용해야 하는지 정리한다.
RSC가 바꾸는 것

서버 컴포넌트는 서버에서 실행되고, 그 결과(HTML + RSC Payload)만 클라이언트에 전달된다. 컴포넌트 코드 자체는 클라이언트 번들에 포함되지 않으므로, 무거운 라이브러리(마크다운 파서, 날짜 포맷터 등)를 자유롭게 사용해도 번들 크기에 영향이 없다.
데이터 페칭이 극적으로 간소화된다. 서버 컴포넌트에서 직접 await db.query()를 호출할 수 있어, useEffect/useState/API 라우트 없이 데이터를 가져온다. 데이터베이스와 가까운 서버에서 쿼리가 실행되므로 지연도 줄어든다.
서버 컴포넌트에서 직접 DB 조회// app/posts/page.tsx — 서버 컴포넌트 (기본) import { db } from '@/lib/db'; export default async function PostsPage() { const posts = await db.post.findMany({ orderBy: { createdAt: 'desc' }, take: 20 }); return ( <ul> {posts.map(post => <li key={post.id}>{post.title}</li>)} </ul> ); }
사용 패턴
핵심 패턴: 서버 컴포넌트를 기본으로 하고, 인터랙션이 필요한 부분만 'use client'로 분리. 데이터 페칭은 서버 컴포넌트에서, 이벤트 핸들러/상태는 클라이언트에서.

흔한 실수
- 모든 컴포넌트에 'use client' 붙이기 (RSC 장점 소멸)
- 서버 컴포넌트에서 useState/useEffect 사용 시도
- 직렬화 불가능한 props 전달 (함수, Date 객체 등)

서버/클라이언트 분리 패턴
핵심 규칙: 인터랙션이 있으면 클라이언트, 없으면 서버. onClick, onChange, useState, useEffect가 필요한 컴포넌트만 'use client'를 붙인다. 데이터를 가져오고 표시만 하는 컴포넌트는 서버에 둔다.
컴포지션 패턴: 서버 컴포넌트가 데이터를 가져오고, 클라이언트 컴포넌트를 children으로 감싼다. 이렇게 하면 데이터 페칭은 서버에서, UI 인터랙션은 클라이언트에서 처리된다.
서버-클라이언트 컴포지션 패턴// ServerWrapper.tsx (서버 컴포넌트) import { db } from '@/lib/db'; import ClientList from './ClientList'; export default async function ServerWrapper() { const items = await db.item.findMany(); return <ClientList items={items} />; } // ClientList.tsx (클라이언트 컴포넌트) 'use client'; export default function ClientList({ items }) { const [filter, setFilter] = useState(''); return <input onChange={e => setFilter(e.target.value)} />; }