프론트엔드/Next.js

(Next.js) CSR vs SSR

그린티_ 2025. 11. 26. 20:43
반응형

서론

웹 개발이랑 면접에서 기술면접에서 CSR, SSR이라는 용어가 자꾸 나옴
React는 CSR이고, Next.js는 SSR도 지원한다고 함
처음엔 "둘 다 HTML인데 뭐가 달라?" 싶었지만, 찾아보니 장단점이 확실히 다름
그래서 CSR과 SSR이 정확히 뭐고, 언제 뭘 써야 하는지 정리해봄

본론

CSR (Client Side Rendering) 이해하기

CSR은 렌더링을 클라이언트(브라우저)에서 함
서버는 빈 HTML과 JavaScript만 보내고, 브라우저가 나머지 일을 함

CSR의 흐름

1. 유저가 웹사이트 접속
   ↓
2. 서버가 빈 HTML 파일 전송
   <html>
     <body>
       <div id="root"></div>
     </body>
   </html>
   ↓
3. 브라우저가 JavaScript 다운로드 및 실행
   ↓
4. JavaScript가 DOM을 동적으로 생성
   React.render(<App />, document.getElementById('root'))
   ↓
5. 완성된 페이지가 화면에 표시

CSR 코드 예시 (React)

// App.js
import { useState, useEffect } from 'react';

export default function App() {
  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 <div>로딩 중...</div>;

  return (
    <div>
      <h1>블로그 글 목록</h1>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </div>
      ))}
    </div>
  );
}

CSR의 장점

  • 개발이 간단함 (React, Vue, Angular 등)
  • 서버 부하가 적음 (서버는 데이터만 보냄)
  • 페이지 간 이동이 빠름 (JavaScript로 DOM만 바꿈)
  • 사용자 상호작용에 즉시 반응

CSR의 단점

  • 초기 로딩이 느림 (JavaScript 다운로드 + 실행 필요)
  • SEO가 좋지 않음 (처음에 빈 HTML이라서 검색 엔진이 내용을 못 봄)
  • 큰 JavaScript 번들 크기

초기 로딩 시간 비교

CSR:  1초 → 2초 → 3초 → 4초(완성) 
      HTML  JS   실행  렌더링

SSR:  1초(완성)
      완성된 HTML

SSR (Server Side Rendering) 이해하기

SSR은 렌더링을 서버에서 함
서버가 완성된 HTML을 만들어서 브라우저에 보냄

SSR의 흐름

1. 유저가 웹사이트 접속
   ↓
2. 서버가 데이터 조회
   ↓
3. 서버가 React 컴포넌트를 HTML로 변환
   (Node.js에서 React를 렌더링)
   ↓
4. 완성된 HTML을 브라우저에 전송
   <html>
     <body>
       <h1>블로그 글 목록</h1>
       <div>
         <h2>첫 번째 글</h2>
         <p>내용...</p>
       </div>
       ...
     </body>
   </html>
   ↓
5. 브라우저가 화면 표시 (매우 빠름)
   ↓
6. 브라우저가 JavaScript 다운로드 및 실행
   (hydration - 상호작용 가능하게 만듦)

SSR 코드 예시 (Next.js)

// pages/posts.js
export default function Posts({ posts }) {
  return (
    <div>
      <h1>블로그 글 목록</h1>
      {posts.map(post => (
        <div key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.content}</p>
        </div>
      ))}
    </div>
  );
}

// 서버에서 실행
export async function getServerSideProps() {
  // 서버에서 데이터 조회
  const response = await fetch('http://localhost:3001/api/posts');
  const posts = await response.json();

  return {
    props: {
      posts
    }
  };
}

SSR의 장점

  • 초기 로딩이 빠름 (완성된 HTML을 바로 받음)
  • SEO가 좋음 (HTML에 모든 내용이 있음)
  • 느린 네트워크나 약한 기기에서도 빨리 보임
  • 검색 엔진이 콘텐츠를 쉽게 크롤링

SSR의 단점

  • 서버 부하가 높음 (매 요청마다 렌더링)
  • 개발이 복잡함 (Node.js 서버 필요)
  • 페이지 간 이동이 느릴 수 있음 (매번 서버에 요청)
  • 확장성 문제 (트래픽 증가 시 서버 자원 부족)

CSR vs SSR 직접 비교

항목 CSR SSR
렌더링 위치 브라우저 서버
초기 로딩 속도 느림 (JS 다운로드 필요) 빠름 (완성된 HTML)
SEO 나쁨 좋음
서버 부하 적음 높음
개발 복잡도 낮음 높음
인터랙션 속도 빠름 (JS만 실행) 느릴 수 있음 (재요청)
필요한 서버 정적 호스팅 (GitHub Pages) Node.js 서버 필요
사용 예시 대시보드, SNS 블로그, 뉴스, 전자상거래

시각적으로 이해하기

CSR - 초기 로딩

시간 →
브라우저 |━━━ JS 다운로드 ━━━|━━━ 파싱 ━━━|━━━ 렌더링 ━━━|
        |                              |
        0초                           5초 (완성)

사용자 입장: 흰 화면만 보여서 답답함

SSR - 초기 로딩

시간 →
서버     |━━ 데이터조회 ━━|━━ 렌더링 ━━|
        |                |
        0초              1초 (완성된 HTML 전송)

사용자 입장: 바로 내용이 보임

함께 사용하면 좋은 경우 (하이브리드 접근)

사실 CSR과 SSR은 배타적이지 않음
둘을 섞어서 사용하면 더 좋은 경우가 많음

예시 1: 초기 로딩은 SSR, 이후는 CSR

// Next.js로 초기 페이지는 SSR
export async function getServerSideProps() {
  const posts = await fetchPosts();
  return { props: { posts } };
}

// 클라이언트에서는 상호작용은 CSR으로
export default function Posts({ posts }) {
  const [filtered, setFiltered] = useState(posts);
  const [search, setSearch] = useState('');

  const handleSearch = (e) => {
    const term = e.target.value;
    setSearch(term);
    // 브라우저에서 즉시 필터링 (SSR과 관계없이)
    setFiltered(
      posts.filter(p => p.title.includes(term))
    );
  };

  return (
    <div>
      <input 
        placeholder="검색..." 
        onChange={handleSearch}
      />
      {filtered.map(post => <Post key={post.id} post={post} />)}
    </div>
  );
}

흐름

  1. 사용자가 페이지 접속 → SSR로 빠르게 초기 콘텐츠 로드
  2. 사용자가 검색 입력 → CSR로 즉시 필터링 (서버 요청 없음)

예시 2: 중요한 콘텐츠는 SSR, 추가 콘텐츠는 CSR

export default function ProductPage({ product }) {
  const [reviews, setReviews] = useState(null);
  const [reviewsLoading, setReviewsLoading] = useState(false);

  const loadReviews = async () => {
    setReviewsLoading(true);
    const data = await fetch(`/api/reviews/${product.id}`);
    setReviews(await data.json());
    setReviewsLoading(false);
  };

  return (
    <div>
      {/* SSR로 미리 받은 상품 정보 - 빠르게 보임 */}
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <p>가격: {product.price}원</p>

      {/* 리뷰는 필요할 때만 CSR로 로드 */}
      <button onClick={loadReviews}>리뷰 보기</button>
      {reviewsLoading && <div>로딩 중...</div>}
      {reviews && reviews.map(r => <Review key={r.id} review={r} />)}
    </div>
  );
}

export async function getServerSideProps(context) {
  const { id } = context.params;
  const product = await fetchProduct(id);
  return { props: { product } };
}

흐름:

  1. 페이지 접속 → SSR로 상품 정보 빠르게 로드 (SEO 좋음)
  2. "리뷰 보기" 클릭 → CSR로 필요할 때만 리뷰 로드

언제 뭘 써야 할까?

CSR을 쓰면 좋을 때

  • 대시보드, 관리자 페이지 (SEO 안 필요)
  • 내가 로그인한 개인 데이터 (미리 렌더링할 수 없음)
  • 실시간으로 자주 업데이트되는 콘텐츠
  • 사용자와의 상호작용이 많은 경우
  • 정적 호스팅만 가능한 경우

SSR을 쓰면 좋을 때

  • 블로그, 뉴스, 문서
  • SEO가 중요한 경우
  • 초기 로딩 속도가 중요한 경우
  • 검색 엔진 크롤링이 필요한 경우

둘 다 같이 쓰는게 좋은 방법!

  • 대부분의 현대적 웹앱 (Next.js, Nuxt 권장)
  • 초기 로딩은 빠르게(SSR), 상호작용은 부드럽게(CSR)

결론

CSR은 브라우저에서 렌더링 → 개발 간단, 상호작용 빠름, 하지만 초기 로딩 느림
SSR은 서버에서 렌더링 → 초기 로딩 빠름, SEO 좋음, 하지만 서버 부하 높음

"뭐가 더 좋아?"라는 질문은 의미 없고, 상황에 맞게 선택하거나 섞어서 써야 함

요즘 트렌드는 SSR의 초기 로딩 속도 + CSR의 상호작용 부드러움을 모두 누리는 하이브리드 방식
Next.js, Nuxt, Remix 같은 풀스택 프레임워크가 이걸 지원하는 이유도 여기 있음

앞으로 웹앱 만들 때 상황에 맞게 CSR, SSR, 그리고 둘의 조합을 잘 활용해야겠음!

반응형