Fork Coding
Blog/March 10, 2026

React 19 서버 컴포넌트 딥다이브

React 19 서버 컴포넌트 딥다이브

React 19의 서버 컴포넌트가 프론트엔드 개발 패러다임을 어떻게 바꾸고 있는지 깊이 있게 살펴봅니다.

Fork Coding·2026년 3월 10일
ReactServer ComponentsNext.js

서버 컴포넌트란?

React 19에서 정식으로 도입된 서버 컴포넌트(Server Components)는 컴포넌트를 서버에서 렌더링하고, 그 결과만 클라이언트에 전달하는 새로운 패러다임입니다. 이를 통해 번들 사이즈를 획기적으로 줄이고, 데이터 페칭을 더 효율적으로 처리할 수 있습니다.

기존 방식의 한계

기존 클라이언트 사이드 렌더링(CSR)에서는 모든 컴포넌트 코드가 클라이언트로 전송되어야 했습니다. 데이터를 가져오기 위해 useEffect와 상태 관리 라이브러리를 조합해야 했고, 이는 불필요한 복잡성을 야기했습니다.

// ❌ 기존 방식: 클라이언트에서 데이터 페칭
"use client";

import { useState, useEffect } from "react";

export function PostList() {
  const [posts, setPosts] = useState([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch("/api/posts")
      .then((res) => res.json())
      .then((data) => {
        setPosts(data);
        setLoading(false);
      });
  }, []);

  if (loading) return <Spinner />;
  return <ul>{posts.map((p) => <li key={p.id}>{p.title}</li>)}</ul>;
}

서버 컴포넌트의 해결책

서버 컴포넌트를 사용하면 컴포넌트 자체에서 직접 async/await로 데이터를 가져올 수 있습니다.

// ✅ 서버 컴포넌트: 서버에서 직접 데이터 페칭
import { db } from "@/lib/db";

export async function PostList() {
  const posts = await db.post.findMany({
    orderBy: { createdAt: "desc" },
  });

  return (
    <ul>
      {posts.map((p) => (
        <li key={p.id}>{p.title}</li>
      ))}
    </ul>
  );
}

핵심 이점

1. 제로 번들 사이즈

서버 컴포넌트의 코드는 클라이언트 번들에 포함되지 않습니다. 무거운 라이브러리(예: marked, highlight.js)를 서버에서만 사용하면 클라이언트 번들 사이즈에 전혀 영향을 주지 않습니다.

2. 직접적인 백엔드 접근

데이터베이스, 파일 시스템, 내부 API에 직접 접근할 수 있어 별도의 API 레이어 없이도 데이터를 가져올 수 있습니다.

3. 자동 코드 스플리팅

"use client" 경계를 기준으로 자동으로 코드 스플리팅이 이루어집니다. 개발자가 수동으로 React.lazy()를 사용할 필요가 줄어듭니다.

실전 패턴

서버-클라이언트 경계 설계

서버 컴포넌트와 클라이언트 컴포넌트를 효과적으로 나누는 것이 핵심입니다:

Page (서버) → Layout (서버) → InteractiveWidget (클라이언트)
                            → StaticContent (서버)
                            → DataTable (서버) → SortButton (클라이언트)

원칙: 인터랙션이 필요한 가장 작은 단위만 클라이언트 컴포넌트로 만듭니다.

Streaming과 Suspense

서버 컴포넌트는 React Suspense와 결합하여 점진적 렌더링을 지원합니다:

import { Suspense } from "react";

export default function Dashboard() {
  return (
    <div>
      <h1>대시보드</h1>
      <Suspense fallback={<ChartSkeleton />}>
        <AnalyticsChart />
      </Suspense>
      <Suspense fallback={<TableSkeleton />}>
        <RecentOrders />
      </Suspense>
    </div>
  );
}

마치며

서버 컴포넌트는 단순한 기능 추가가 아니라, 웹 애플리케이션을 설계하는 방식 자체를 변화시키는 패러다임 전환입니다. Next.js App Router와 함께 사용하면 그 진가를 충분히 발휘할 수 있습니다.

서버에서 할 수 있는 일은 서버에서 하고, 클라이언트에서만 할 수 있는 일(인터랙션, 브라우저 API)만 클라이언트에 맡기세요. 이 원칙을 지키면 자연스럽게 더 빠르고, 더 가벼운 애플리케이션을 만들 수 있습니다.