I_TStory/TIL

CSR, SSR, SSG… 이젠 진짜 확실히 구분해보자!

귤치 2025. 4. 24. 13:45

“이 페이지는 CSR로 구현돼서 SEO가 약해요.”
“SSR로 바꾸면 첫 페이지 로딩이 더 빨라질 수도 있어요.”
“SSG로 미리 렌더링해서 정적 페이지로 배포해요.”

CSR, SSR, SSG가 어떻게 다르고, 언제 어떤 걸 써야 하는지 헷갈리는 경우 많은데
오늘 이 글로 한 방에 정리해보자


1. CSR (Client Side Rendering)

브라우저(클라이언트)에서 JS로 화면을 만드는 방식

어떻게 작동하나요?:

  1. 사용자가 페이지에 접속하면
  2. 브라우저는 HTML 틀(div#root)만 받고
  3. JS 번들을 다운받은 후 그때서야 화면이 보이기 시작함

대표 예시:

  • React 앱을 Vite/CRA로 만들었을 때
  • SPA(Single Page Application) 대부분

장점

  • 빠른 페이지 전환 (앱처럼 동작)
  • 백엔드 없이도 작동 가능

단점

  • JS가 로딩되기 전까진 빈 화면
  • 검색엔진이 콘텐츠 못 읽는 경우 있음 (SEO 약함)

2. SSR (Server Side Rendering)

서버에서 HTML을 만들어서 브라우저에 보내주는 방식

어떻게 작동하나요?:

  1. 사용자가 페이지에 접속하면 서버가 즉시 필요한 데이터를 가져옴
  2. 서버가 HTML을 만들어서 브라우저에 보내줌
  3. 사용자는 즉시 화면을 볼 수 있음

대표 예시:

  • Next.js의 getServerSideProps
  • 쇼핑몰, 뉴스 사이트 (초기 로딩과 SEO 중요할 때)

장점

  • SEO에 좋음 (검색엔진이 HTML 읽을 수 있음)
  • 첫 화면 로딩 빠름

단점

  • 서버 부하가 큼
  • 매 요청마다 서버가 렌더링해야 함 → 느려질 수 있음

3. SSG (Static Site Generation)

빌드 타임에 미리 HTML을 만들어두고, 서버 없이 서빙

어떻게 작동하나요?:

  1. 배포 전에 빌드하면 HTML 파일이 미리 만들어짐
  2. 요청 시 서버는 그냥 그 정적 파일을 보내줌

대표 예시:

  • 블로그, 문서 사이트, 마케팅 랜딩페이지
  • Next.js의 getStaticProps

장점

  • 속도 빠름 (CDN으로 정적 파일 그대로 전달)
  • 트래픽 많아도 서버 부담 거의 없음

단점

  • 동적 데이터 처리 어려움 (빌드 후 데이터가 바뀌면 반영이 안 됨)
  • 페이지 수가 많으면 빌드 오래 걸림

번외편: ISR (Incremental Static Regeneration)

SSG인데, 필요할 때만 서버에서 다시 만들어주는 방식

Next.js가 만든 하이브리드 전략

  • HTML을 미리 만들어두고 일정 시간이 지나면 서버가 백그라운드에서 재생성

완전한 정적 + 최신 데이터 반영을 동시에 잡고 싶을 때 사용


언제 어떤 걸 써야 할까?

SEO 중요, 첫 로딩 빠르게 SSR
콘텐츠가 자주 안 바뀜 SSG or ISR
로그인/인증 기반 앱 CSR or SSR
모든 게 실시간 CSR or SSR
블로그, 문서, 마케팅 SSG 

Next.js 기준 렌더링 방식 요약

CSR useEffect, 클라이언트 컴포넌트 완전 클라이언트에서 처리
SSR getServerSideProps 요청마다 HTML 생성
SSG getStaticProps 빌드 시 HTML 생성
ISR getStaticProps + revalidate 정적 + 일정 시간마다 재생성

마무리

렌더링 방식은 성능 + SEO + 사용자 경험 + 서버 비용까지 다 엮인 문제
정답은 없고 상황에 따라 최적의 전략을 조합해서 쓰는 게 중요

 


+ 번외

 

nextjs 12 버전 (페이지 라우터) 에서 SSG가(정적 사이트 생성) 기본적으로 설정돼있음.

근데 왜 getServerSideProps 를 쓰냐 ?

동적 seo가 적용 안되기 때문임. (pages/[id].tsx와 같은 동적 페이지)

getServerSideProps 쓸 땐 페이지 요청시마다 서버에서 페이지를 리렌더링

(getServerSideProps 안써도 리렌더링 되지만 그건 서버에서 주는게 아니라 그냥 리액트의 상태 업데이트 때문에 리렌더링 되는 것임)

 

그래서.. 동적 페이지까지 seo 하고싶다면 getServerSideProps 사용하면 될 것 같다 흠

 

(근데그럼 getStaticProps 쓰는 이유는 뭐지 ha..)

 


next 13 ~ 버전 (App Router) 에서는 기본적으로 SSR이 적용

하지만 서버 컴포넌트클라이언트 컴포넌트를 명확히 구분할 수 있기 때문에,

서버에서 렌더링하는 방식(SSR)과 클라이언트에서 렌더링하는 방식(CSR)을 상황에 맞게 선택가능

1. 기본 SSR 동작

앱 라우터에서 서버 컴포넌트를 사용하면, 페이지나 컴포넌트가 서버에서 렌더링

이 방식은 SSR과 동일한 방식으로 동작. 서버에서 데이터를 가져와서 페이지를 렌더링한 후, 클라이언트에 전달됨

 

// app/clientside.tsx
'use client';

import { useState } from 'react';

export default function ClientSide() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
}
 

이 방식은 매 요청 시마다 서버에서 데이터를 가져오고 렌더링하기 때문에 SSR로 간주됨

2. 클라이언트 컴포넌트 사용 시

Next.js 13에서는 클라이언트 컴포넌트를 별도로 지정해야함

use client라는 지시어를 사용하면, 해당 컴포넌트는 클라이언트에서만 실행됨.

이렇게 지정된 컴포넌트는 CSR 방식으로 동작함

// app/clientside.tsx
'use client';

import { useState } from 'react';

export default function ClientSide() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <p>Count: {count}</p>
    </div>
  );
}
 

use client' 지시어를 사용하면 이 컴포넌트는 클라이언트에서만 렌더링됨. 이 경우, CSR 방식으로 페이지가 렌더링

결론

  • 앱 라우터에서는 기본적으로 SSR이 적용됨. 즉, 서버 컴포넌트를 사용하면 서버에서 렌더링되고, 이 방식이 기본
  • 하지만 클라이언트 컴포넌트를 사용하면 CSR 방식으로 동작하게 되며, 이때는 서버 렌더링이 이루어지지 않음
  • SSR을 적용한 페이지는 매 요청 시마다 서버에서 새롭게 렌더링됨