Next.js App Router 심화 - Server Component vs Client Component언제 쓸까?

2026. 5. 2. 07:50·AI

Next.js App Router 심화
Server Component vs Client Component
언제 쓸까?

이 선택을 틀리면 성능, 보안, 유지보수가 한꺼번에 무너집니다.
"Client Component는 예외다" — 이 기준 하나로 구조가 달라집니다.

⚡ 2026년 4월 최신 기준 🛠 실무 판단 기준 제공 🔗 Supabase·RLS·SaaS 연결

📋 목차

  1. 이 선택이 틀리면 어떤 일이 생기는가
  2. 기존 React의 한계와 App Router의 패러다임 전환
  3. Server Component vs Client Component 핵심 비교
  4. 렌더링 흐름 전체 이해 — 서버에서 브라우저까지
  5. 왜 Server Component가 기본인가 — 체감 성능·SEO·보안
  6. Client Component — 언제 쓰고 남용하면 어떻게 되는가
  7. 실무 판단 기준 — 3단계 질문으로 즉시 결정
  8. 실무 패턴 — Server → Client 구조와 Server Actions
  9. Supabase와의 연결 — 풀스택의 완성
  10. 자주 하는 실수 4가지
  11. 실전 체크리스트 & 핵심 정리
  12. FAQ

Next.js 13 이후 App Router를 처음 접한 개발자들이 공통적으로 막히는 지점이 있습니다. "이 컴포넌트는 서버에서 써야 하나요, 클라이언트에서 써야 하나요?" 처음에는 단순한 선택처럼 보이지만, 이 판단이 틀리는 순간 성능 저하, 보안 구멍, 번들 사이즈 폭발, 유지보수 지옥이 동시에 찾아옵니다. 단순한 실수가 아닙니다. 구조 자체가 무너지는 문제입니다.

이 글은 개념 설명으로 끝나지 않습니다. 코드를 작성하기 전, "이 컴포넌트를 어디에 둘까?"를 3초 안에 결정할 수 있는 실무 판단 기준을 드립니다. 그리고 이 기준을 제대로 이해하면, 다음 시리즈인 Supabase 연동, RLS 보안, SaaS 아키텍처가 자연스럽게 연결됩니다. 이 글은 시리즈 전체의 기초 체력입니다.

🎯 이 글의 핵심 기준

"Client Component는 '예외'다.
대부분의 코드는 Server Component로 작성해야 한다."

1. 이 선택이 틀리면 어떤 일이 생기는가

많은 개발자들이 App Router를 처음 쓸 때 습관적으로 모든 컴포넌트에 "use client"를 붙입니다. 에러가 사라지니까요. 하지만 이 순간 App Router의 장점이 통째로 사라집니다.

💣 잘못된 선택이 만드는 3가지 폭탄

  • 성능 붕괴: 불필요한 JS가 번들에 포함되어 초기 로딩이 눈에 띄게 느려집니다. 특히 모바일에서 치명적입니다.
  • 보안 구멍: 서버에서만 써야 할 API 키, DB 접속 정보가 클라이언트 번들에 노출될 수 있습니다.
  • 유지보수 지옥: 컴포넌트 경계가 무너지면 "이 코드가 어디서 실행되는지" 파악하기 어려워져 버그 추적이 불가능해집니다.

💬 "App Router에서 컴포넌트 선택을 잘못하면 성능, 보안, 유지보수 모두 무너질 수 있습니다."

2. 기존 React의 한계와 App Router의 패러다임 전환

기존 Pages Router에서 무슨 일이 있었나

기존 React와 Next.js Pages Router에서는 모든 컴포넌트가 기본적으로 클라이언트에서 실행됐습니다. 서버 사이드 작업은 getServerSideProps·getStaticProps 같은 특별 함수를 통해서만 가능했습니다. 결과는 세 가지 문제였습니다.

  • 번들 사이즈 폭발: 사용자가 쓰지도 않는 라이브러리 코드까지 브라우저가 내려받아야 했습니다
  • SEO 불리: 클라이언트 렌더링이 기본이라 크롤러가 빈 HTML을 먼저 보게 됩니다
  • API 키 노출: 서버에서만 쓸 로직이 클라이언트 번들에 포함되는 사고가 발생했습니다

App Router의 선언 — "이제 React는 서버에서 시작한다"

Next.js 13+의 App Router는 Server Component를 기본값으로 채택했습니다. app/ 디렉토리 안의 모든 컴포넌트는 별도 선언이 없으면 서버에서 실행됩니다. 이것이 패러다임 전환의 핵심입니다. 클라이언트 컴포넌트는 더 이상 기본값이 아니라, 명시적으로 요청해야 하는 예외가 됐습니다.

Pages Router: "React는 클라이언트다" → App Router: "React는 서버에서 시작한다"

3. Server Component vs Client Component 핵심 비교

판단 기준 Server Component Client Component
실행 위치 서버 브라우저
선언 방법 기본값 (선언 불필요) "use client" 필수
useState / useEffect ❌ 불가 ✅ 가능
이벤트 핸들러 (onClick 등) ❌ 불가 ✅ 가능
async/await 데이터 패칭 ✅ 최적 ⚠ 비효율 (useEffect 필요)
JS 번들 포함 여부 ❌ 포함 안 됨 (빠름) ✅ 번들에 포함 (느림)
API 키 / 환경변수 ✅ 안전 (노출 없음) ❌ 노출 위험
브라우저 API (window 등) ❌ 사용 불가 ✅ 가능

Next.js Server Component와 Client Component 실행 위치·번들 포함·API 키 보안 비교

4. 렌더링 흐름 전체 이해 — 서버에서 브라우저까지

Server Component와 Client Component가 실제로 어떤 흐름으로 동작하는지 이해하지 못하면, 판단 기준이 흔들립니다. 아래 흐름을 한 번만 제대로 이해하면 이후 모든 판단이 쉬워집니다.

전체 렌더링 흐름

STEP 1 · 서버

🖥 Server Component 실행

DB 쿼리 / API 호출 / HTML 생성
JS 번들 포함 없음 · API 키 안전

↓

STEP 2 · 전송

📦 완성된 HTML + 최소 JS 번들 전달

Server Component 코드는 전송 안 됨
Client Component 코드만 번들에 포함

↓

STEP 3 · 브라우저

🌐 Client Component Hydration

useState · 이벤트 핸들러 활성화
사용자 인터랙션 준비 완료

↓

STEP 4 · 사용자 액션

👆 User Interaction

클릭 / 입력 / 폼 제출

↓

STEP 5 · 서버

⚡ Server Action 실행

별도 API Route 없이 서버 로직 처리
Supabase INSERT / UPDATE

↓

STEP 6 · 데이터

🗄 DB (Supabase)

RLS 보안 적용 · 데이터 변경 완료

이 흐름에서 핵심은 하나입니다. Server Component는 처음부터 끝까지 서버에 머물고, 결과(HTML)만 브라우저로 이동합니다. Client Component는 Hydration을 통해 브라우저에서 활성화되며, 사용자 액션이 발생하면 Server Action을 통해 다시 서버로 연결됩니다. 이 흐름이 보이면 어디에 무엇을 둬야 하는지 자연스럽게 판단됩니다.

5. 왜 Server Component가 기본인가 — 체감 성능·SEO·보안

⚡ 성능 — JS 번들 감소 → 체감될 정도로 빠른 로딩

Server Component의 코드는 브라우저로 전송되지 않습니다. 예를 들어 마크다운 파서(remark, 수백 KB)나 날짜 라이브러리(date-fns)를 Server Component에서만 사용하면 번들에 아예 포함되지 않습니다. 클라이언트 번들이 줄어들면 초기 로딩 속도가 체감될 정도로 빨라집니다. 특히 3G 모바일 환경에서 그 차이는 수 초 단위입니다.

🔍 SEO — 크롤러가 콘텐츠를 즉시 인식

Server Component는 완성된 HTML을 서버에서 만들어 전달합니다. 검색 엔진 크롤러는 JS 실행을 기다리지 않고 즉시 콘텐츠를 읽을 수 있습니다. 블로그, 상품 상세 페이지, 랜딩 페이지처럼 SEO가 매출과 직결되는 페이지에서 Server Component는 선택이 아닌 필수입니다.

🔐 보안 — API 키와 서버 로직이 브라우저에 도달하지 않는다

Supabase 서비스 키, OpenAI API 키, DB 접속 문자열 등 민감한 정보를 Server Component 안에서 사용하면 클라이언트 번들에 절대 포함되지 않습니다. 브라우저 DevTools의 Network 탭을 아무리 뒤져도 이 정보는 보이지 않습니다. 별도 보안 처리 없이 구조 자체로 보안이 확보됩니다.

💬 "Server Component는 성능 + SEO + 보안을 구조 자체로 해결한다"

6. Client Component — 언제 쓰고 남용하면 어떻게 되는가

Client Component를 반드시 써야 하는 3가지 경우

  • 폼 입력 / 실시간 반응: 사용자가 타이핑할 때마다 UI가 변해야 하는 경우 (검색창, 필터, 폼 유효성 검사)
  • 클릭·드래그 등 이벤트: onClick, onSubmit, onDrag 같은 브라우저 이벤트가 필요한 경우
  • 상태 관리 / 사이드 이펙트: useState, useReducer로 로컬 상태를 관리하거나, useEffect로 DOM 조작이 필요한 경우

// Client Component — 인터랙션이 있을 때만 선언

"use client"

import {'{ useState }'} from 'react'

export default function SearchBar() {'{'}

const [query, setQuery] = useState('')

return <input value={'{query}'} onChange={'(e) => setQuery(e.target.value)'} />

{'}'}

⚠️ Client Component를 남용하면 벌어지는 일

"use client"를 파일 최상단에 선언하면 해당 파일의 모든 자식 컴포넌트까지 Client로 전환됩니다. 레이아웃 파일에 하나 잘못 넣으면 페이지 전체가 클라이언트 번들에 포함됩니다. Client Component를 남용하는 순간, App Router의 성능·보안·SEO 장점이 통째로 사라집니다.

  • 번들 사이즈가 급격히 증가 → 모바일 초기 로딩 체감 저하
  • 서버에서 렌더링되어야 할 콘텐츠가 클라이언트로 이동 → SEO 타격
  • API 키와 서버 로직이 번들에 포함될 위험 → 보안 사고

📌 핵심 원칙: "Client Component는 '예외'다. 최소 단위로, 꼭 필요한 곳에만 선언하라."

7. 실무 판단 기준 — 3단계 질문으로 즉시 결정

컴포넌트를 만들기 전, 아래 세 가지 질문에 순서대로 답하세요. 대부분의 판단은 이 세 질문으로 끝납니다.

① 데이터 중심인가? (fetch, DB 쿼리, API 호출)

→ Server Component. async/await를 컴포넌트 최상위에서 바로 쓸 수 있습니다. API 키도 안전하고, 결과가 HTML로 즉시 완성됩니다.

② 인터랙션 중심인가? (클릭·입력·상태 변화)

→ Client Component. "use client"를 선언하고, 해당 컴포넌트만 분리합니다. 부모 레이아웃이나 페이지 전체를 Client로 만들지 않도록 주의합니다.

③ 둘 다 필요한가? (데이터 패칭 + 인터랙션)

→ 분리하세요. 데이터 패칭은 Server Component에서, UI 상태 관리는 내부 Client Component로 분리합니다. Server → Client로 props를 내려주는 패턴을 사용합니다.

⚠️ "하나의 컴포넌트에 데이터 패칭과 인터랙션을 같이 넣으려는 순간, 구조가 무너지기 시작합니다. 역할을 분리하는 것이 App Router 설계의 핵심입니다."

Next.js App Router 컴포넌트 선택 판단 기준 — 데이터·인터랙션·분리 3단계 플로우차트

8. 실무 패턴 — Server → Client 구조와 Server Actions

패턴 1: Server → Client 데이터 전달

가장 기본적이고 강력한 패턴입니다. 서버에서 데이터를 가져와 props로 Client Component에 내려줍니다.

// app/dashboard/page.tsx — Server Component (기본값, "use client" 없음)

import {'{ UserList }'} from './UserList'


export default async function DashboardPage() {'{'}

const users = await fetchUsers() // 서버에서 DB 직접 접근, API 키 안전

return <UserList users={'{users}'} /> // props로 Client에 전달

{'}'}


// components/UserList.tsx — Client Component (인터랙션만 담당)

"use client"

export function UserList({'{ users }'}) {'{'}

const [selected, setSelected] = useState(null) // UI 상태만 담당

// 데이터 패칭 없음 — 이미 props로 받았음

{'}'}

✅ 이 패턴을 일관되게 지키면 상태 관리 라이브러리(Redux, Zustand) 없이도 대부분의 데이터 흐름을 해결할 수 있습니다. 서버가 데이터의 단일 진실 공급원이 되기 때문입니다.

패턴 2: Server Actions — 프론트와 백엔드의 경계를 바꾸다

🔥 2026 트렌드: Server Actions는 API Route를 줄이는 것이 아니라 구조 자체를 바꿉니다

기존에는 클라이언트에서 서버로 데이터를 보내려면 반드시 API Route(/api/users)를 만들어야 했습니다. Server Actions는 이 경계를 흐립니다. 서버에서 실행되는 함수를 클라이언트에서 직접 호출할 수 있습니다. 프론트엔드 코드 안에 백엔드 로직이 자연스럽게 통합되는 구조입니다.

SERVER ACTIONS 흐름

Client Component (버튼 클릭) → Server Action (서버에서만 실행) → Supabase DB
별도 API Route 불필요 · "use server" 선언 하나로 해결

// actions.ts — Server Action ("use server" 선언)

"use server"


export async function createUser(formData: FormData) {'{'}

const name = formData.get('name')

await supabase.from('users').insert({'{ name }'}) // 서버에서만 실행됨

{'}'}

9. Supabase와의 연결 — 풀스택의 완성

💡 시리즈 핵심 메시지

"Supabase는 Server Component와 Server Actions 구조와 결합될 때,
별도 백엔드 서버 없이 풀스택 개발이 가능합니다."

이 구조를 이해하면 Supabase 연동이 왜 Server Component 중심으로 설계되는지 바로 납득됩니다. 각 역할을 정확히 분담하면 Express나 FastAPI 같은 별도 백엔드 없이 Next.js + Supabase만으로 프로덕션 수준의 SaaS를 만들 수 있습니다.

Supabase 작업 컴포넌트 타입 이유
.select() 데이터 읽기 Server Component 서비스 키 안전, HTML로 즉시 렌더링
.insert() .update() 쓰기 Server Action API Route 없이 서버 로직 실행
.channel().on() 실시간 Client Component 브라우저 WebSocket 연결 필요
auth.getUser() 인증 확인 Server Component 서버에서 쿠키 기반 세션 검증, 빠른 리다이렉트

🔗 시리즈 연결 구조

① App Router 이해 (이 글) → ② Supabase 연동 → ③ RLS 보안 → ④ SaaS 아키텍처
이 글의 Server Component 개념이 흔들리면 뒤의 모든 글이 이해되지 않습니다.

Next.js App Router와 Supabase 풀스택 아키텍처 — 별도 백엔드 없이 SaaS 구현 구조도

10. 자주 하는 실수 4가지

"기본을 client로 두는 순간 구조가 무너진다"는 말처럼, 실무에서 반복적으로 나타나는 실수들입니다. 미리 알고 피하세요.

❌ 실수 1: 모든 컴포넌트에 습관적으로 "use client" 추가

에러를 빠르게 없애려고 "use client"를 무분별하게 붙이는 경우입니다. 이 순간 App Router의 모든 장점이 사라집니다. "use client"는 반드시 필요한 가장 작은 단위에만, 의도적으로 선언해야 합니다.

❌ 실수 2: Client Component에서 useEffect로 데이터 패칭

useEffect 안에서 fetch()를 호출하면 초기 렌더링 → JS 실행 → useEffect 실행 → 재렌더링 순서로 발생해, 화면이 깜빡이고 로딩이 느립니다. Server Component에서 async/await로 처리하면 이 문제 자체가 사라집니다.

❌ 실수 3: API 키를 Client Component에서 사용

NEXT_PUBLIC_ 없이 선언된 환경변수는 Client에서 undefined가 됩니다. 반대로 NEXT_PUBLIC_으로 선언하면 브라우저에 완전 노출됩니다. 민감한 API 키는 반드시 Server Component나 Server Action에서만 사용하세요.

❌ 실수 4: Server Component에서 브라우저 API 사용 (window, localStorage 등)

Server Component는 서버(Node.js)에서 실행됩니다. 브라우저에만 존재하는 window, localStorage, document, navigator는 서버에 존재하지 않으므로 즉시 에러가 발생합니다. 이런 API가 필요한 로직은 반드시 Client Component로 분리해야 합니다.

// ❌ Server Component에서 — 런타임 에러 발생

const theme = localStorage.getItem('theme') // ReferenceError!

// ✅ Client Component로 분리

"use client" // 상단에 선언 후 localStorage 사용 가능

11. 실전 체크리스트

✅ 컴포넌트 작성 전 즉시 확인 리스트

  • 이 컴포넌트에 useState / useEffect가 반드시 필요한가? → 없으면 Server 유지
  • 클릭, 입력, 드래그 등 브라우저 이벤트가 있는가? → 있으면 Client 선언
  • DB 쿼리나 API 호출이 있는가? → Server Component에서 async/await로 처리
  • "use client"를 선언했다면, 자식 컴포넌트도 전부 Client가 된다는 걸 인지했는가?
  • window, localStorage, document 등 브라우저 API가 있는가? → Client Component만 가능
  • API 키는 NEXT_PUBLIC_ 없이 선언되어 Server에서만 사용 중인가?
  • 데이터 + 인터랙션 둘 다 필요하다면 → Server와 Client 컴포넌트로 분리했는가?
  • Server Action을 쓴다면 → "use server" 선언, 별도 API Route가 없어도 된다는 걸 인지했는가?

📌 핵심 정리

  • App Router에서 모든 컴포넌트는 기본적으로 Server Component다. Client는 예외다.
  • Client Component를 남용하면 App Router의 성능·SEO·보안 장점이 통째로 사라진다.
  • Server Component는 체감 성능, SEO, API 키 보안을 구조 자체로 해결한다.
  • 판단 기준은 단순하다: 데이터 중심이면 Server, 인터랙션 중심이면 Client, 둘 다라면 분리한다.
  • Server Actions는 API Route를 줄이는 것이 아니라 프론트와 백엔드의 경계 자체를 바꾼다.
  • Supabase는 Server Component + Server Actions 구조와 결합해야 진짜 풀스택이 완성된다.
  • 이 구조를 이해하면 Supabase, RLS, SaaS 아키텍처가 자연스럽게 연결된다.

FAQ

Q1. Next.js App Router에서 Server Component와 Client Component를 한 페이지에 같이 쓸 수 있나요?

네, 함께 사용하는 것이 오히려 정상적인 실무 패턴입니다. Server Component 안에 Client Component를 자식으로 포함할 수 있습니다. 단, 반대 방향(Client Component 안에 Server Component를 직접 import)은 불가능합니다. 일반적으로 페이지 수준은 Server, 폼·버튼·상태가 필요한 가장 작은 부분만 Client로 분리합니다.

Q2. Next.js App Router에서 Client Component를 최소화하면 성능이 실제로 얼마나 개선되나요?

Vercel의 공개 사례에 따르면, 대형 마크다운 파서나 차트 라이브러리를 Server Component로 이동하면 클라이언트 JS 번들이 수백 KB 단위로 줄어듭니다. 실제 측정 기준으로는 LCP(Largest Contentful Paint)가 1초 이상 개선되는 경우도 보고됩니다. 특히 저성능 모바일 기기에서 그 차이는 체감될 정도로 명확합니다.

Q3. Next.js Server Actions와 API Route의 차이점 — 언제 Server Actions를 써야 하나요?

Server Actions는 Next.js 내부에서만 호출되는 서버 함수로, 외부에 HTTP 엔드포인트가 노출되지 않습니다. 폼 제출, 버튼 클릭 시 DB 쓰기처럼 외부 공개 API가 필요 없는 내부 서버 로직에 적합합니다. 반면 API Route는 모바일 앱이나 외부 서비스가 직접 호출해야 하는 공개 엔드포인트에 사용합니다. Supabase 기반 SaaS 프로젝트에서는 대부분 Server Actions로 충분합니다.

Q4. Next.js App Router에서 Supabase 인증을 Server Component로 처리하면 어떤 이점이 있나요?

@supabase/ssr 패키지를 사용하면 Server Component에서 쿠키 기반으로 사용자 세션을 검증할 수 있습니다. 가장 큰 이점은 미인증 사용자를 서버 수준에서 즉시 리다이렉트할 수 있다는 점입니다. 클라이언트에서 인증 상태를 체크하면 JS 실행 후 리다이렉트되어 미인증 콘텐츠가 잠깐 노출될 수 있지만, 서버 인증은 HTML 응답 전에 처리되므로 보안과 UX 모두 훨씬 뛰어납니다.

시리즈 계속 보기

이 구조가 이해됐다면,
다음은 Supabase 연동입니다

Server Component에서 Supabase를 연결하고,
RLS로 사용자별 데이터를 보호하는 실전 구조를 다음 글에서 다룹니다.

이 구조를 이해하면 Supabase, RLS, SaaS 아키텍처가 자연스럽게 연결됩니다.

📘 다음 글: Supabase Next.js 연동 완전 가이드
🔐 이후 글: Supabase RLS 실전 설정 — 사용자별 데이터 보호
🏗 최종 글: Next.js + Supabase SaaS 아키텍처 설계

구독하면 시리즈 전체를 놓치지 않습니다 (추후 업로드 예정)👆

'AI' 카테고리의 다른 글

Claude Code 설치 후 바로 써먹는 실전 초기 세팅 완전 가이드  (0) 2026.05.04
PDF 넣으면 핵심만 뽑아주는 AI 사용법 (2026 최신 완전 정리)  (0) 2026.05.03
Vercel 무료 배포 완전 가이드 —Next.js 프로젝트 10분 만에 올리기  (0) 2026.05.02
Next.js App Router 완전 정복 —Supabase 로그인·DB까지 최단 경로  (0) 2026.05.02
멀티모달 AI, 이제 하나로 통합된다-엔비디아 Nemotron이 AI 구조를 바꾸는 방식  (0) 2026.05.01
'AI' 카테고리의 다른 글
  • Claude Code 설치 후 바로 써먹는 실전 초기 세팅 완전 가이드
  • PDF 넣으면 핵심만 뽑아주는 AI 사용법 (2026 최신 완전 정리)
  • Vercel 무료 배포 완전 가이드 —Next.js 프로젝트 10분 만에 올리기
  • Next.js App Router 완전 정복 —Supabase 로그인·DB까지 최단 경로
Arahant
Arahant
  • Arahant
    MANI
    Arahant
    • 분류 전체보기 (58) N
      • 시사 (4)
      • 라이프 (4)
      • AI (50) N
  • 인기 글

  • 태그

    1인AI미디어
    1인사업자자동화
    1인크리에이터도구
    1인크리에이터자동화
    2026AI개발자
    2026AI개발자취업
    2026AI트렌드
    2026개발자취업
    2026웹개발
    2026웹개발트렌드
  • 최근 글

  • 블로그 메뉴

    • 홈
    • about
    • contact
    • 개인정보 처리방침
  • hELLO· Designed By정상우.v4.10.6
Arahant
Next.js App Router 심화 - Server Component vs Client Component언제 쓸까?
상단으로

티스토리툴바