TechFeedTechFeed
Frontend

React Server Components 실전 가이드

한 줄 요약: React Server Components(RSC)는 서버에서 렌더링되어 클라이언트 번들에 포함되지 않는 컴포넌트로, 번들 크기 감소와 데이터 페칭 간소화가 핵심 장점이다. RSC는 React 18에서 도입되고 Next.js App Router에서 기본값이 된 패러다임이다. React Server Components는 서버에서만 실행되는 컴포넌트 입니다.

by

한 줄 요약: React Server Components(RSC)는 서버에서 렌더링되어 클라이언트 번들에 포함되지 않는 컴포넌트로, 번들 크기 감소와 데이터 페칭 간소화가 핵심 장점이다.


RSC는 React 18에서 도입되고 Next.js App Router에서 기본값이 된 패러다임이다. 기존 클라이언트 컴포넌트와 어떻게 다르고, 실전에서 어떻게 사용해야 하는지 정리한다.


RSC가 바꾸는 것

React Server Components는 서버에서만 실행되는 컴포넌트입니다. JavaScript 번들에 포함되지 않아 클라이언트 번들 크기가 줄고, DB나 파일 시스템에 직접 접근할 수 있습니다.


RSC가 바꾸는 것 — 프레임워크 성능 벤치마크
React Server Components 실전 가이드 — 프레임워크 성능 벤치마크 (출처: 공식 문서 및 벤치마크 데이터 기반)

서버 컴포넌트는 서버에서 실행되고, 그 결과(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'로 분리. 데이터 페칭은 서버 컴포넌트에서, 이벤트 핸들러/상태는 클라이언트에서.


사용 패턴 — 컴포넌트 아키텍처 다이어그램
React Server Components 실전 가이드 — 컴포넌트 아키텍처 다이어그램 (출처: 공식 문서 및 벤치마크 데이터 기반)

흔한 실수

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

흔한 실수 — 렌더링 파이프라인 비교
React Server Components 실전 가이드 — 렌더링 파이프라인 비교 (출처: 공식 문서 및 벤치마크 데이터 기반)

서버/클라이언트 분리 패턴

핵심 규칙: 인터랙션이 있으면 클라이언트, 없으면 서버. 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)} />; }
주의: 서버 컴포넌트에서 클라이언트 전용 API(window, document, localStorage)를 사용하면 빌드 에러가 발생한다. 또한 서버 컴포넌트 간에 상태를 공유할 수 없으므로, 전역 상태가 필요하면 클라이언트 컴포넌트로 분리해야 한다.

1인 개발자 관점에서 이 주제가 왜 중요한가

이 글의 주제(React Server Components 실전 가이드)를 다룰 때 저는 Next.js + Vercel 조합으로 12개 사이트를 운영하면서 겪은 실측 이슈 관점에서 봅니다. 단순히 새 기능을 소개하는 입장이 아니라, 12개 한국어 사이트를 1인으로 운영하면서 매일 클로드 코드를 켜두고 작업하는 입장이라 의사결정의 기준이 다소 좁고 실용적인 편입니다. 신기술이 출시될 때마다 곧바로 도입하기보다는 우선 한두 사이트에 시범 도입해 두고, 운영 부담이 늘지 않는지 며칠 지켜본 뒤 전체 확산을 결정하는 식입니다.


가장 자주 보는 변수는 1인 개발자의 현금흐름 한계, 그리고 한국 결제 시 VAT 10% 환급 절차입니다. 두 변수는 신기술을 도입할지 말지 결정할 때 거의 매번 영향을 줍니다. 글의 본문은 위의 두 축을 직접 명시하지는 않지만, 본문에서 다루는 항목을 이 축에 비춰 보시면 본인 환경에 맞는지 빠르게 판단할 수 있습니다. 특히 버셀 무료 티어 한도 vs 유료 전환 시점 같은 운영 변수는 도구 자체 성능보다 더 큰 영향을 주는 경우가 많기 때문에 본문 비교표를 볼 때 같이 떠올리시면 좋습니다.


한 가지 더 강조하면, Frontend 영역의 글을 읽을 때 저는 본문이 다루는 도구·서비스가 ① 한국 결제 가능 여부 ② 한국어 응답 품질 ③ 종량제 비용의 예측 가능성 ④ 1인 개발자 학습 시간 대비 효과, 네 항목을 모두 충족해야 실제 도입을 결정합니다. 네 항목 중 하나라도 명확하지 않으면 도입을 1~2주 미루는 편이고, 그 사이 같은 카테고리의 다른 글도 확인합니다.


본문의 각 비교·코드·체크리스트는 이 네 항목 중 어느 부분에 영향을 주는지 의식하면서 보시면 더 빠르게 결론에 도달하실 수 있습니다. 본 사이트의 다른 Frontend 글과 함께 보시면 같은 평가 축이 반복되는 것을 확인하실 수 있습니다. 토픽 페이지 또는 같은 카테고리 태그를 따라가시면 동일한 평가 기준이 적용된 글을 한 번에 모아 보실 수 있습니다.


본인 환경에 적용하기 전 확인할 체크포인트

본문의 내용을 본인 환경에 적용하기 전에 다음 항목을 빠르게 확인하시면 도입 실패 가능성을 줄일 수 있습니다.


  • 공식 문서 버전 일치 — 본문 작성 시점과 현재 배포 버전이 다른 경우, 같은 명령어가 다르게 동작할 수 있습니다.
  • 한국 결제·환율 검증 — 카드 결제, 부가가치세 처리, 원화 환산 시점에 따라 실제 청구액이 본문 예시와 다를 수 있습니다.
  • 기존 스택과의 호환성 — Next.js·Vercel·Supabase 같은 기본 스택과 충돌이 없는지 패키지 의존성을 먼저 확인하세요.
  • 롤백 절차 사전 정리 — 도입 후 문제가 생겼을 때 1회 명령으로 이전 상태로 되돌릴 수 있는 절차를 도입 전에 메모해 두시면 운영 부담이 크게 줄어듭니다.

위 네 항목을 모두 통과하면 보통 1~2시간 내에 도입을 마칠 수 있고, 통과하지 못한 항목이 있다면 그 항목을 우선 해결한 뒤 다시 시작하는 것이 효율적입니다.


자주 묻는 질문

가장 자주 발생하는 실수나 함정은 무엇인가요?

가장 흔한 실수는 습관적으로 모든 컴포넌트 맨 위에 'use client'를 붙이는 것입니다. 그러면 RSC의 핵심 장점인 번들 축소가 통째로 사라져 무거운 마크다운 파서나 날짜 포맷터가 다시 클라이언트로 딸려 갑니다. 반대로 서버 컴포넌트에서 useState·useEffect를 쓰려다 에러를 만나는 경우, window·document·localStorage 같은 클라이언트 전용 API를 서버 컴포넌트에서 호출해 빌드가 깨지는 경우도 잦습니다. 또 함수나 Date 객체를 props로 클라이언트에 넘기면 직렬화 단계에서 막힙니다. 전역 상태가 필요하면 서버 컴포넌트끼리 상태를 공유할 수 없으니 클라이언트 컴포넌트로 분리해야 한다는 점도 함께 기억하시기 바랍니다.


다른 대안과 비교했을 때 어떤 상황에 적합한가요?

RSC가 빛을 보는 자리는 데이터를 가져와 보여주기만 하는 페이지입니다. 목록·상세·대시보드처럼 DB 조회 결과를 그대로 렌더링하고 인터랙션이 적은 화면이라면, await db.query()를 컴포넌트 안에서 바로 호출해 useEffect나 별도 API 라우트를 없앨 수 있고 무거운 마크다운 파서·날짜 포맷터를 써도 번들이 늘지 않습니다. 반대로 화면 대부분이 폼 입력, 드래그, 실시간 상태 갱신처럼 클릭·키보드 인터랙션 중심이라면 어차피 클라이언트 컴포넌트로 채워야 하므로 RSC의 번들 절감 효과가 거의 없습니다. SPA 라우팅에 강하게 의존하거나 App Router로 옮길 수 없는 기존 Pages Router 프로젝트라면 무리한 전환보다 현행 유지가 낫습니다.


더 깊게 공부하려면 어떤 자료를 보면 좋을까요?

가장 먼저 React 공식 문서의 Server Components 챕터와 Next.js 공식 문서의 Server and Client Components 페이지를 권합니다. 두 문서가 'use client' 경계, 서버-클라이언트 컴포지션, 직렬화 가능한 props 같은 핵심 규칙을 가장 정확하게 설명합니다. 한 단계 더 들어가려면 streaming과 Suspense를 묶어 다루는 React의 Suspense 문서, 그리고 RSC Payload가 어떻게 직렬화돼 클라이언트로 전달되는지 설명하는 React Server Components 아키텍처 글(RFC 포함)을 읽어 보세요. 키워드로는 server actions, partial prerendering, streaming SSR을 검색하면 다음 학습 흐름이 자연스럽게 이어집니다.


React Server Components 실전 가이드, 한 줄로 정리하면 어떻게 되나요?

React Server Components는 서버에서만 실행돼 JavaScript 번들에 포함되지 않는 컴포넌트로, 클라이언트 번들을 줄이고 컴포넌트 안에서 직접 DB를 조회하게 해 데이터 페칭을 간소화합니다. 실무 원칙은 '서버 컴포넌트가 기본, 인터랙션이 필요한 부분만 use client로 분리'이며, 서버가 데이터를 가져와 클라이언트 컴포넌트를 children으로 감싸는 컴포지션이 핵심 패턴입니다. 결국 onClick·useState가 없는 표시 전용 컴포넌트는 서버에 두고, 함수나 Date처럼 직렬화 불가능한 값을 경계 너머로 넘기지 않는 것이 전부입니다.


실무에서 처음 도입할 때 가장 먼저 확인할 것은 무엇인가요?

'서버가 기본, 클라이언트는 예외'라는 경계선을 먼저 정하세요. onClick·onChange·useState·useEffect가 필요한 컴포넌트에만 'use client'를 붙이고, 데이터를 가져와 표시만 하는 컴포넌트는 서버에 둡니다. 그러면 await db.query()를 컴포넌트 안에서 바로 호출해 useEffect/useState/API 라우트 없이 데이터를 가져올 수 있습니다. 그다음으로 확인할 것은 서버에서 클라이언트로 넘기는 props인데, 함수나 Date 객체처럼 직렬화되지 않는 값은 경계를 넘지 못하니 직렬화 가능한 형태로 바꿔야 합니다. 컴포지션이 필요하면 서버 컴포넌트가 데이터를 받아 클라이언트 컴포넌트를 children으로 감싸는 패턴을 기본으로 잡으시기 바랍니다.


reactserver-componentsRSCnextjs성능

관련 도구

함께 보면 좋은 문제 해결

관련 포스트