LogoSEO Jing
  • All Posts
  • SEO Jing
  • okayJing
  • KD Team
  • CLab CoreTeam
  • Study

Contact Me

© 2026 SEOJing. All rights reserved.

프론트엔드스터디Next.jsCSRSSRSSGISRWeb Vitals웹 퍼포먼스

프론트엔드 스터디 대면 9주차: Next.js 렌더링 진화와 웹 퍼포먼스

2026년 5월 25일·19분 읽기

1. 화면은 어디서 만들어지는가

지금까지 React로 화면을 만드는 방법을 배웠습니다. 그런데 React로 만든 화면은 어디서 실제로 그려질까요? 브라우저일 수도 있고, 서버일 수도 있습니다. 이 차이가 사용자가 첫 화면을 보는 속도에 직접 영향을 줍니다.

오늘은 렌더링 방식이 어떻게 진화해왔는지와, 퍼포먼스를 숫자로 측정하는 법을 봅니다. 7주차에 짧게 언급했던 Next.js가 왜 이 선택들을 제공하는지 이해하는 시간이기도 합니다.


2. Next.js는 무엇이고, 왜 쓰는가

본격적으로 CSR, SSR 같은 렌더링 방식을 보기 전에 먼저 Next.js가 무엇인지부터 정리하고 가겠습니다. React는 UI 라이브러리입니다. 버튼, 카드, 페이지처럼 화면을 컴포넌트로 나누고 상태에 따라 다시 그리는 데 집중합니다. 그런데 실제 서비스는 화면만으로 끝나지 않습니다.

페이지 주소를 어떻게 나눌지, 첫 화면 HTML을 어디서 만들지, 검색엔진이 내용을 읽을 수 있게 할지, 이미지를 어떻게 최적화할지, 서버에서 데이터를 가져올지, 배포 환경에서는 어떤 코드가 어디서 실행될지까지 같이 결정해야 합니다.

Next.js는 React 위에 이런 서비스 운영에 필요한 선택지를 얹은 프레임워크

라고 보면 됩니다.

React와 Next.js의 차이

구분ReactNext.js
핵심 역할UI를 컴포넌트로 만들기React 앱을 서비스 구조로 만들기
라우팅별도 라이브러리 필요파일/폴더 기반 라우팅 제공
렌더링주로 브라우저에서 JS로 그림CSR/SSR/SSG/ISR 등 선택 가능

포스트 목록

/study/clab-26-1/in-person
파일 9개, 폴더 0개
프론트엔드 스터디 대면 0주차: 프론트엔드 개발자란? 그리고 우리가 배울 것들프론트엔드 스터디 대면 1주차: HTML 마크업과 폼, 그리고 CSS의 시작프론트엔드 스터디 대면 2주차: 폼(Form), CSS 선택자, 그리고 박스 모델프론트엔드 스터디 대면 3주차: 박스 모델 실전, Position과 Flexbox프론트엔드 스터디 대면 6주차(1): HTML/CSS/JS 리마인드와 브라우저 렌더링프론트엔드 스터디 대면 6주차(2): AI 시대의 개발 방식과 프론트엔드 개발자의 위치프론트엔드 스터디 대면 7주차: React 입문과 프로젝트 구조프론트엔드 스터디 대면 8주차: API와 통신 — 프론트엔드와 백엔드의 계약프론트엔드 스터디 대면 9주차: Next.js 렌더링 진화와 웹 퍼포먼스
데이터 처리클라이언트 fetch 중심으로 시작서버 컴포넌트, 캐싱, revalidate 등 제공
배포/인프라직접 결정할 부분이 많음Vercel/Edge/서버리스 흐름과 잘 맞음

한 줄로 정리하면, React가 화면을 어떻게 만들지에 집중한다면, Next.js는 그 화면을 어디서 만들고 어떻게 사용자에게 전달할지 까지 다룹니다. 그래서 Next.js를 배운다는 건 단순히 문법을 하나 더 배우는 것이 아니라, 프론트엔드 코드가 브라우저 밖의 서버·캐시·배포 환경과 어떻게 이어지는지 보는 일에 가깝습니다.

왜 그냥 React만 쓰면 안 될까?

작은 관리자 페이지나 내부 도구라면 React만으로도 충분할 수 있습니다. 하지만 블로그, 쇼핑몰, 모집 페이지처럼 첫 화면 속도와 SEO가 중요한 서비스라면 문제가 달라집니다. 사용자가 페이지에 들어왔을 때 빈 HTML을 받고 JS가 전부 실행될 때까지 기다려야 한다면, 느린 네트워크에서는 첫 인상이 나빠집니다. 검색엔진도 내용을 바로 읽기 어렵습니다.

Next.js는 이 문제를 해결하려고 "이 페이지는 빌드할 때 미리 만들자", "이 페이지는 요청이 올 때 서버에서 만들자", "이 컴포넌트는 서버에서만 실행하고, 클릭이 필요한 버튼만 브라우저로 보내자" 같은 선택지를 제공합니다. 오늘 다루는 CSR, SSR, SSG, ISR, Server Component가 전부 이 질문에서 출발합니다.

문법보다 먼저 봐야 할 질문

  • 이 화면은 검색엔진이 읽어야 하나요?
  • 데이터는 자주 바뀌나요, 거의 고정되어 있나요?
  • 사용자가 처음 봐야 하는 핵심 콘텐츠는 무엇인가요?
  • 클릭, 입력, 상태 변화가 필요한 영역은 어디인가요?
  • 이 코드는 브라우저에서 실행되어야 하나요, 서버에서 실행되어야 하나요?

제가 생각했을 때 Next.js를 처음 배울 때 가장 중요한 건 API 이름을 외우는 것이 아니라, 위 질문을 자연스럽게 떠올리는 것입니다. 렌더링 방식은 이름을 외우기 위한 분류가 아니라, 이런 질문에 답하기 위한 선택지입니다.

3. CSR — 브라우저가 직접 그리는 방식

React로 만든 앱을 아무 설정 없이 배포하면 CSR(Client-Side Rendering) 방식으로 동작합니다. 서버는 빈 HTML과 JS 파일만 보내고, 브라우저가 JS를 실행해서 직접 화면을 만듭니다.

서버 → 빈 HTML 전송 → JS 다운로드 → JS 실행 → DOM 생성 → 화면 표시
html
<!-- 서버가 보내는 HTML (실제로 이게 전부) -->
<html>
  <body>
    <div id="root"></div>
    <script src="/bundle.js"></script>
  </body>
</html>

사용자는 JS가 다운로드되고 실행되기 전까지 빈 화면을 봅니다. JS가 클수록, 인터넷이 느릴수록, 화면이 늦게 뜹니다.

  • 장점: 첫 로딩 후 페이지 이동이 빠르고, 서버 부하가 적음
  • 단점: 첫 화면이 늦게 뜸, 검색 엔진이 내용을 읽기 어려움(SEO)

4. SSR — 서버가 먼저 그려주는 방식

SSR(Server-Side Rendering)은 서버가 HTML을 미리 완성해서 보내줍니다. 사용자는 JS가 로드되기 전에 이미 화면 내용을 볼 수 있습니다.

서버에서 HTML 완성 → 완성된 HTML 전송 → 화면 즉시 표시 → JS 다운로드 → Hydration
지표CSRSSR
FCP (첫 콘텐츠가 보이는 시점)느림 (JS 실행 후)빠름 (HTML 도착 즉시)
SEO불리 (빈 HTML)유리 (완성된 HTML)
서버 부하없음매 요청마다 생성

SSR이 "빠르다"는 건 정확히는 사용자가 화면을 처음 보는 시점이 빠르다는 뜻입니다. 클릭이나 입력 같은 인터랙션이 되려면 Hydration이 끝나야 합니다.


5. Hydration — 정적 HTML에 생명 불어넣기

서버가 보낸 HTML은 그림처럼 보이기만 합니다. 클릭해도 반응이 없습니다. Hydration은 이 정적 HTML에 JS 이벤트 핸들러를 붙여서 실제로 동작하게 만드는 과정입니다.

정적 HTML (보이지만 클릭해도 반응 없음)
        ↓ JS 다운로드 + Hydration
동적 HTML (클릭, 입력 등 가능)

Hydration이 진행되는 동안 사용자는 화면은 보이지만 인터랙션이 안 되는 어색한 구간을 경험할 수 있습니다. 이 구간을 줄이는 것이 현대 렌더링 최적화의 핵심 중 하나입니다.


6. Next.js 렌더링 전략의 진화

Next.js는 SSR만 하는 게 아닙니다. 페이지마다 다른 렌더링 전략을 선택할 수 있고, 그 전략들이 이렇게 진화해왔습니다.

CSR → SSR → SSG → ISR → Streaming SSR → PPR

SSG (Static Site Generation) — 빌드 시 미리 만들기

서버가 요청마다 HTML을 만드는 SSR과 달리, SSG는 빌드할 때 HTML을 미리 만들어둡니다. 요청이 오면 서버가 만들 필요 없이 미리 만든 파일을 바로 보냅니다.

[SSR] 요청 → 서버가 HTML 생성 → 전송 (매번)
[SSG] 빌드 → HTML 생성 → CDN에 올림 → 요청 → 바로 전송 (빠름)
  • 장점: 가장 빠름, 서버 부하 없음
  • 단점: 데이터가 바뀌면 전체를 다시 빌드해야 함

ISR (Incremental Static Regeneration) — 필요할 때만 갱신

SSG의 단점을 해결합니다. 일정 시간마다 그 페이지만 조용히 재생성합니다. 1000페이지 중 요청이 온 1페이지만 갱신되는 식입니다.

tsx
// Next.js에서 ISR 설정
export const revalidate = 60; // 60초마다 재생성
0~60초:   캐시 그대로 반환 (SSG처럼 빠름)
60초 후:  요청이 오면 기존 캐시 반환 + 백그라운드에서 새 HTML 생성
          → 다음 요청부터 새 HTML 서빙

Streaming SSR — 준비된 것부터 조각씩 보내기

일반 SSR은 페이지 전체가 준비될 때까지 기다렸다가 한번에 보냅니다. DB 조회가 느린 경우 사용자는 그만큼 기다려야 합니다. Streaming SSR은 준비된 부분부터 먼저 보내고, 느린 부분은 나중에 채워줍니다.

tsx
<Layout>
  <Header /> {/* 즉시 전송 */}
  <Suspense fallback={<CommentSkeleton />}>
    <Comments /> {/* DB 조회 끝나면 전송, 그 전엔 Skeleton 표시 */}
  </Suspense>
</Layout>

Suspense는 "아직 준비 안 됐으면 대신 이걸 보여줘"를 선언하는 React 컴포넌트입니다. Skeleton은 콘텐츠가 들어올 자리를 미리 잡아두는 빈 뼈대 UI입니다.

PPR (Partial Prerendering) — 컴포넌트별로 정적/동적 분리

ISR은 페이지 전체를 정적 또는 동적으로 취급합니다. PPR은 한 페이지 안에서 컴포넌트 단위로 정적/동적을 나눕니다. 상품 이름·이미지는 정적으로, 가격·재고는 동적으로.

tsx
export default function ProductPage() {
  return (
    <div>
      {/* 정적: 빌드 시 생성, CDN에서 즉시 전송 */}
      <ProductName />
      <ProductImage />

      {/* 동적: 요청 시 서버에서 생성, 준비되면 Streaming */}
      <Suspense fallback={<PriceSkeleton />}>
        <Price />

전략 비교

속도데이터 신선함어울리는 콘텐츠
SSG가장 빠름빌드 시점 고정블로그, 문서, 변경 없는 페이지
SSR느림항상 최신로그인 필요, 실시간 데이터
ISRSSG와 동일

7. 서버 컴포넌트 vs 클라이언트 컴포넌트

Next.js App Router에서는 컴포넌트가 어디서 실행되는지를 직접 선택할 수 있습니다. 이것이 RSC(React Server Components)입니다.

tsx
// Server Component (기본값)
// 서버에서만 실행됨. 브라우저로 JS가 안 감.
async function PostList() {
  const posts = await db.query("SELECT * FROM posts");
  return (
    <ul>
      {posts.map((p) => (
        <li key={p.id}>{p.title}</li>
      ))}
    </ul

판단 기준은 하나입니다. 이 컴포넌트가 클릭, 입력, 상태 변화를 다루는가? 그렇지 않다면 Server Component로 두는 게 낫습니다. JS 번들에 포함되지 않으니 번들 크기가 줄고, Hydration 대상도 줄어 성능이 좋아집니다.

구분Server ComponentClient Component
실행 위치서버브라우저
useState, onClick❌ 불가✅ 가능
DB 직접 접근✅ 가능❌ 불가
JS 번들 포함❌ 포함 안 됨

8. Web Vitals — "빠르다"를 숫자로 말하기

Google이 정한 사용자 체감 성능의 3가지 핵심 지표입니다. 검색 순위(SEO)에도 실제로 영향을 줍니다.

LCP (Largest Contentful Paint)

가장 큰 콘텐츠가 화면에 나타나는 시간. 메인 이미지, 큰 텍스트 블록이 해당합니다.

페이지 요청
  │  0.5s  헤더, 네비게이션 표시
  │  1.2s  메인 이미지 표시 ← 이게 LCP
  │  1.8s  나머지 콘텐츠

좋음: ≤ 2.5s / 개선 필요: 2.5~4s / 나쁨: > 4s
  • SSG나 SSR은 LCP를 빠르게 만들고, CSR은 느리게 만드는 주요 원인입니다.

INP (Interaction to Next Paint)

사용자가 클릭·입력한 뒤 화면이 반응하기까지의 시간.
사용자가 버튼 클릭
  │  JS 이벤트 핸들러 실행
  │  상태 업데이트
  │  DOM 변경 + 화면 다시 그림 ← 여기까지가 INP

좋음: ≤ 200ms / 나쁨: > 500ms
  • Hydration이 무거우면 JS 메인 스레드가 막혀서 INP가 나빠집니다.
  • Server Component를 늘리면 Hydration 대상이 줄어 INP가 개선됩니다.

CLS (Cumulative Layout Shift)

페이지 로딩 중 레이아웃이 얼마나 흔들리는가. 광고가 갑자기 끼어들어서 읽던 텍스트가 밀리는 경험이 대표적입니다.

좋음: ≤ 0.1 / 나쁨: > 0.25
  • 흔한 원인: 이미지 크기 미지정, 폰트 로딩 후 텍스트 크기 변화
  • 해결: width/height 명시, Skeleton으로 공간 미리 확보
지표측정하는 것좋음 기준주요 영향 요소
LCP콘텐츠 표시 속도≤ 2.5s렌더링 방식(SSG/SSR vs CSR), 이미지 크기
INP인터랙션 반응 속도≤ 200msJS 번들 크기, Hydration 무게
CLS레이아웃 안정성

9. 퍼포먼스 측정하는 방법

Web Vitals는 실제로 어떻게 측정할까요? Chrome DevTools에 이미 다 있습니다.

Lighthouse

Chrome DevTools → Lighthouse 탭 → "Analyze page load" 버튼. LCP, INP, CLS를 포함한 퍼포먼스 점수와 개선 제안을 한번에 볼 수 있습니다.

  • Mode: Navigation — 페이지 첫 로딩 시 측정 (가장 일반적)
  • Device: Mobile로 체크하면 더 엄격하게 측정됨

Performance 탭

Chrome DevTools → Performance 탭 → 녹화 버튼 후 페이지 조작. 타임라인에서 어느 시점에 뭐가 실행됐는지, 어디서 병목이 생겼는지 볼 수 있습니다.

Network 탭으로 렌더링 방식 확인하기

Network 탭에서 첫 HTML 응답을 열어보면 렌더링 방식을 가늠할 수 있습니다.

  • HTML 응답에 내용이 가득 → SSR 또는 SSG
  • HTML 응답에 빈 div만 → CSR

실제로 해보기

  1. 크롬에서 아무 사이트나 열고 DevTools → Lighthouse 실행
  2. LCP / INP / CLS 점수 확인
  3. "Opportunities" 섹션에서 개선 제안 읽기
  4. Network 탭으로 첫 HTML 응답 확인 — 내용이 있는지 없는지

10. 정리 — 렌더링 선택의 기준

어떤 렌더링 방식을 쓸지는 "이 페이지의 데이터가 얼마나 자주 바뀌는가"와 "인터랙션이 중요한가"로 판단합니다.

  • 데이터가 거의 안 바뀐다 → SSG
  • 실시간 데이터가 필요하다 → SSR
  • 가끔 바뀌는 데이터 → ISR
  • 페이지 일부만 실시간 → PPR + Streaming
  • 클릭·입력이 필요한 컴포넌트만 → Client Component

렌더링 방식을 잘 선택하는 것 자체가 프론트엔드 성능 최적화의 절반입니다.


11. 스터디 마무리 — 여기서 무엇을 가져가야 하나

원래 계획대로라면 이후 주차에서 팀 협업과 배포 이야기를 더 이어가려 했지만, 일정상 이번 9주차를 마지막 대면으로 정리합니다. 그래서 오늘은 단순히 "Next.js 렌더링 종류를 외우는 시간"이 아니라, 지금까지 배운 프론트엔드 개념들이 실제 서비스로 이어질 때 어떤 질문으로 바뀌는지 보는 시간입니다.

마지막 기준은 이렇습니다. 화면을 만들 때는 데이터가 어디서 오고, HTML은 어디서 만들어지고, 사용자가 언제 상호작용할 수 있는지를 같이 생각해보세요. CSR/SSR/SSG/ISR/PPR은 이름을 외우기 위한 분류가 아니라, 이 질문에 답하기 위한 선택지입니다.

마지막 체크리스트

  • 이 페이지는 검색엔진이 읽어야 하는가? → SSR/SSG/ISR 고려
  • 데이터는 얼마나 자주 바뀌는가? → SSG/ISR/SSR 선택
  • 클릭과 입력이 필요한 부분은 어디인가? → Client Component 범위 최소화
  • 첫 화면에서 가장 큰 콘텐츠는 무엇인가? → LCP 기준으로 이미지/HTML 확인
  • 화면은 떴는데 클릭이 늦지 않은가? → Hydration과 JS 번들 크기 확인

이후 React와 Next.js를 혼자 공부할 때, 오늘 내용을 다시 꺼내보면 좋습니다. "이 문법을 왜 쓰지?"에서 멈추지 말고 "이 코드가 사용자에게 어떤 화면으로, 어떤 속도로 전달되지?"까지 이어서 보는 것이 이번 스터디의 마지막 목표입니다.


관련 포스팅

  • 이번 주 학습 자료(week9)
  • vinext는 왜 빠를까? — SSR, Vite, Edge, Web Vitals까지 (참고)

</Suspense>
</div>
);
}
약간의 지연
블로그, 상품 목록
PPRSSG급컴포넌트별상품 상세, 대시보드
>
);
}
// Client Component ('use client' 선언 필요)
// 브라우저에서 실행됨. onClick, useState 사용 가능.
("use client");
function LikeButton() {
const [liked, setLiked] = useState(false);
return <button onClick={() => setLiked(true)}>좋아요</button>;
}
✅ 포함됨
≤ 0.1
이미지 크기, Skeleton, 폰트