Next.js의 탄생 배경과 CSR vs SSR vs SSG 이해

현대 웹 생태계에서 '속도'와 '사용자 경험(UX)'은 비즈니스의 생존과 직결됩니다. 하지만 우리는 오랫동안 한쪽을 얻으면 한쪽을 포기해야 하는 선택의 기로에 서 있었습니다. React가 가져온 **CSR(Client Side Rendering)**의 부드러운 전환과 **SSR(Server Side Rendering)**의 초기 로딩 속도 사이에서 말이죠.
Next.js는 이 고질적인 고민을 해결하기 위해 등장했습니다. 단순히 "프레임워크"라는 이름을 넘어, 각 상황에 맞는 최적의 렌더링 전략을 개발자가 요리사처럼 골라 쓸 수 있게 해주는 '도구 모음집'과 같습니다.
1. Deep Dive: 왜 Next.js인가? (렌더링의 3대장 이해하기)
웹 페이지가 화면에 그려지는 방식은 크게 세 가지로 나뉩니다. 이를 일상적인 '음식 배달' 상황에 비유해 보겠습니다.
🏠 CSR (Client Side Rendering): "밀키트 배달"
- 작동 원리: 서버는 텅 빈 HTML과 거대한 JavaScript 파일을 보냅니다. 브라우저(클라이언트)가 이 스크립트를 실행해 화면을 직접 조립합니다.
- 비유: 요리 재료(데이터)와 조리법(JS)을 집으로 배달받아 사용자가 직접 요리해 먹는 방식입니다. 첫 요리 시간은 걸리지만, 한 번 요리 기구를 세팅하면 다음 요리는 아주 빠릅니다.
- 문제점: 검색 엔진(SEO) 로봇이 방문했을 때 빈 냄비(빈 HTML)만 보고 돌아갈 수 있습니다.
🍱 SSR (Server Side Rendering): "완조리 배달"
- 작동 원리: 사용자가 요청할 때마다 서버가 즉시 HTML을 그려서 완성된 상태로 보냅니다.
- 비유: 주문 즉시 주방장이 요리해서 따끈따끈한 상태로 배달해 주는 맛집입니다.
- 특징: 항상 최신 데이터를 보여주지만, 요청이 몰리면 서버 주방장이 과부하에 걸릴 수 있습니다.
🥫 SSG (Static Site Generation): "통조림 배달"
- 작동 원리: 빌드 타임(배포 전)에 미리 HTML을 다 만들어 둡니다.
- 비유: 미리 만들어 둔 통조림을 꺼내 주는 방식입니다.
- 특징: 배달 속도가 세상에서 제일 빠르지만, 내용물을 바꾸려면 통조림을 다시 제작(재빌드)해야 합니다.
2. Hands-on: 실전 이커머스 상품 페이지 구현
Next.js의 진가는 한 서비스 안에서 페이지별로 다른 전략을 취할 수 있다는 점에 있습니다. 상품 목록은 자주 바뀌지 않으니 SSG로, 사용자의 장바구니나 실시간 재고는 SSR이나 CSR로 처리하는 식이죠.
아래는 Next.js(App Router 기준)에서 상품 상세 페이지를 구현하는 예시입니다.
// app/products/[id]/page.js
import { fetchProductDetail } from '@/lib/api';
// 1. 서버 컴포넌트로 기본 렌더링 방식 설정 (SSR/SSG)
export default async function ProductPage({ params }) {
const { id } = params;
// 서버에서 데이터를 직접 페칭 (Next.js의 fetch는 기본적으로 캐싱 지원)
const product = await fetchProductDetail(id);
if (!product) return <div>상품을 찾을 수 없습니다.</div>;
return (
<div className="product-container">
{/* SEO에 최적화된 HTML이 서버에서 생성됨 */}
<h1>{product.name}</h1>
<img src={product.imageUrl} alt={product.name} />
<p>{product.description}</p>
<p className="price">가격: {product.price}원</p>
{/* 클라이언트 컴포넌트 분리: 상호작용이 필요한 부분만 CSR로 처리 */}
<AddToCartButton productId={product.id} />
</div>
);
}
/**
* [Troubleshooting Tip]
* 질문: "상세 페이지인데 SSG로 미리 만들 순 없나요?"
* 답변: generateStaticParams 함수를 사용하면 미리 정의된 ID 목록에 대해
* 빌드 시점에 HTML을 생성할 수 있습니다. 수만 개의 상품이 있다면
* dynamicParams = true 설정을 통해 요청 시 생성(ISR)하는 전략을 추천합니다.
*/
3. Trade-offs: 무엇을 고려해야 하는가?
모든 기술에는 대가가 따릅니다. Next.js가 만능 열쇠는 아닙니다.
- 서버 리소스 비용: SSR을 과도하게 사용하면 클라이언트가 할 일을 서버가 떠안게 됩니다. 서버 트래픽 비용과 사양을 고려해야 합니다.
- 하이드레이션(Hydration) 문제: 서버에서 보낸 HTML과 클라이언트에서 렌더링한 결과가 다를 때(예: new Date() 사용 등) 에러가 발생할 수 있습니다. 시간이나 랜덤 값 처리에 주의가 필요합니다.
- 러닝 커브: 단순한 SPA(Single Page Application) 라이브러리보다 파일 시스템 기반 라우팅, 서버 컴포넌트 개념 등 익혀야 할 규칙이 많습니다.
4. 결론 및 제언
Next.js는 단순히 'React를 편하게 쓰는 도구'를 넘어, 성능과 개발 생산성의 합의점을 찾아주는 프레임워크입니다.
- 블로그나 뉴스처럼 정적인 콘텐츠가 많다면 SSG를.
- 관리자 대시보드처럼 보안과 개인화된 데이터가 중요하다면 CSR을.
- 커머스나 예약 사이트처럼 실시간 정보와 SEO가 모두 중요하다면 SSR을.
여러분의 프로젝트는 현재 어떤 옷을 입고 있나요? 혹시 모든 페이지에 무거운 JS를 쏟아붓고 있지는 않은지, 혹은 너무 정적인 방식에 갇혀 실시간성을 놓치고 있지는 않은지 점검해 볼 때입니다.