Server/Client 경계

서버 클라이언트 컴포넌트 경계

Next.js App Router에서 서버 컴포넌트와 클라이언트 컴포넌트를 섞을 때 핵심은 어디서 렌더링하느냐가 아니라 어떤 값이 직렬화되어 넘어가고 어떤 상호작용이 브라우저에 남아야 하는지다. 경계가 넓으면 번들이 커지고, 경계가 좁으면 props 계약이 선명해진다.

서버 소유 DB, secret, 정적 조합은 서버 컴포넌트에 남긴다
직렬화 경계 props는 JSON으로 넘길 수 있는 plain data로 좁힌다
클라이언트 island state, event, browser API가 필요한 부분만 use client로 둔다
01

데이터 소유 결정

DB, 파일, secret이 필요한 데이터는 서버 컴포넌트에서 가져온다.

클라이언트로 비밀값을 넘기지 않는다
02

상호작용 분리

click, input, local state, browser API가 필요한 부분만 클라이언트 컴포넌트로 자른다.

use client는 파일 전체를 경계로 만든다
03

props 직렬화

서버에서 클라이언트로 넘기는 값이 JSON 직렬화 가능한지 확인한다.

함수, class instance, Date 처리를 조심한다
04

작은 island 만들기

큰 페이지 전체를 client로 바꾸지 않고 버튼, 폼, 탭 같은 상호작용 영역만 분리한다.

번들 크기를 줄인다
05

hydration 확인

서버 markup과 클라이언트 첫 상태가 달라지지 않는지 로컬 시간, 랜덤값, window 접근을 점검한다.

차이는 경고보다 사용자 튐으로 보인다
Server
데이터와 보안 비밀키, DB 접근, 정적 데이터 조합은 서버 쪽에 남긴다.
클라이언트 번들에 포함되지 않는다
Client
상호작용 useState, useEffect, event handler, browser API가 필요할 때 사용한다.
필요한 부분만 작게 만든다
Props
직렬화 계약 경계를 넘는 값은 plain data로 정리한다.
서버 함수는 Server Action 같은 별도 경로가 필요하다
Bundle
전송 비용 상위 파일에 use client를 붙이면 하위 import까지 클라이언트 번들에 들어갈 수 있다.
경계를 아래로 내린다

조합 확인

번들 영향 use client를 붙인 파일이 불필요하게 큰 라이브러리를 끌고 오지 않는지 본다.
직렬화 오류 서버에서 넘긴 props가 함수나 class instance 때문에 실패하지 않는지 확인한다.
비밀값 환경 변수와 서버 전용 데이터가 클라이언트 코드에 섞이지 않았는지 검색한다.