Next.js 교재 · 16편 · 렌더링 모드

ISR·SSG·SSR 차이 — 어떤 렌더링을 고르나

똑같은 페이지가 빌드 타임에 굳기도, 매 요청 새로 그려지기도 한다. 그 선택의 기준.

세 렌더링 모드의 타이밍 차이 컨셉 일러스트

Next.js 의 페이지는 같은 코드여도 언제 HTML 이 만들어지느냐로 모드가 갈린다. 빌드 타임에 한 번 만들고 끝(SSG), 일정 주기마다 다시 만듦(ISR), 매 요청 새로 만듦(SSR). 셋 다 SEO 친화적인 정적 HTML 이 나가지만 신선도와 비용이 다르다.

App Router 가 옛 Pages Router 와 가장 크게 다른 점이 — 모드를 페이지 단위가 아니라 fetch 단위로도 결정할 수 있다는 것. 이번 편에서 셋의 차이와 결정 트리를 정리한다.

1. 세 모드의 정체

모드HTML 만드는 타이밍장점단점
SSG빌드 타임 한 번초고속 (CDN 그대로)데이터 바뀌면 재배포 필요
ISR빌드 + N초마다 재생성속도 + 신선도 절충N초 동안 옛 데이터 가능
SSR매 요청마다항상 최신서버 부하·응답 늦음

(CSR — 클라이언트 렌더링도 있지만 App Router 에선 거의 안 씀. 옛 SPA 패턴.)

2. SSG — 정적 생성

가장 빠르고 가장 단순. 빌드 타임에 HTML 을 만들어 CDN 에 둔다. 사용자가 오면 그냥 정적 파일 응답.

// app/about/page.tsx — 기본이 SSG export default function AboutPage() { return <main>…</main>; } // 또는 fetch 캐시 명시 export default async function BlogIndex() { const posts = await fetch('https://api.example.com/posts', { cache: 'force-cache', // 빌드 타임 캐시 }).then(r => r.json()); return …; }

적합한 곳 — 회사 소개·약관·정책·블로그 글(자주 안 바뀜)·마케팅 페이지. 거의 모든 정적 사이트 생성기(Hugo·Astro·Jekyll)가 같은 결.

한계 — 데이터가 바뀌면 빌드 다시 해야. 1000 페이지면 빌드가 분 단위가 된다.

3. ISR — 점진적 정적 재생성

SSG 의 속도에 시간 기반 갱신을 더한 모드. 첫 빌드 후, 정해진 주기로 백그라운드에서 재생성. Next.js 가 처음 도입한 컨셉이라 자랑할 만하다.

// 60초마다 자동 갱신 export default async function NewsPage() { const news = await fetch('https://api.example.com/news', { next: { revalidate: 60 }, }).then(r => r.json()); return …; } // 또는 페이지 전체 단위로 export const revalidate = 60;

동작 — 사용자가 오면 캐시된 HTML 즉시 응답 (빠름). 동시에 백그라운드에서 60초 후 다시 fetch 해 새 HTML 생성. 다음 사용자는 새 버전. 이벤트 기반 무효화도 가능 — Server Action 에서 revalidatePath('/news') 호출하면 즉시 캐시 폐기.

적합한 곳 — 뉴스·인기 글·상품 목록·실시간이 아닌 동적 데이터. SSG 와 SSR 의 중간점.

revalidate 값 정하기 — 데이터 신선도와 비용의 트레이드오프. 뉴스·트렌드는 60~300초, 상품·가격은 600~3600초, 자주 안 바뀌면 86400초(하루). 0(=no-store)은 SSR 과 같으니 무의미.

4. SSR — 매 요청 동적 생성

매 요청마다 서버가 HTML 을 새로 만든다. 가장 느리지만 가장 최신.

// 명시적 SSR export const dynamic = 'force-dynamic'; // 또는 fetch 옵션 export default async function DashboardPage() { const stats = await fetch('https://api.example.com/me/stats', { cache: 'no-store', }).then(r => r.json()); return …; }

Next 15 부터 cache: 'no-store'기본이다. 옛 14 에선 force-cache 가 기본이었어서, 마이그레이션 시 가장 자주 부딪치는 변화.

적합한 곳 — 사용자별 다른 대시보드·실시간 가격·재고·맞춤 추천. 사용자 별로 다르거나 초 단위로 바뀌어야 하는 데이터.

SSR 가 비싼 이유 — 매 요청마다 서버 계산 + DB 호출. 동시 사용자 1000명이면 동시 SSR 1000번. Vercel 같은 서버리스 환경은 자동 스케일링되지만 함수 호출 비용이 누적. 가능하면 ISR 이나 SSG 로 흡수, 정말 동적인 부분만 SSR.

5. 결정 트리 — 5초 안에 고르기

새 페이지 만들 때 이 순서로 결정.

  1. 사용자별로 다른가? (로그인 사용자별 대시보드 같은 거) → SSR.
  2. 초 단위로 변하는가? (실시간 시세·재고) → SSR.
  3. 분/시간 단위로 변하는가? (뉴스·인기 글·상품 목록) → ISR (revalidate).
  4. 거의 안 변하는가? (블로그 글·약관·소개) → SSG (기본).

실전 — 한 사이트도 페이지마다 다르다. 회사 소개는 SSG, 뉴스 목록은 ISR 5분, 사용자 대시보드는 SSR. 옛 Pages Router 가 페이지 단위 모드였다면, App Router 는 같은 페이지 안에서도 컴포넌트별·fetch 별로 모드 다르게 가능 → 더 세밀한 최적화.

요약 — 16편 좌표

여기까지 정리. 3가지 렌더링 모드 — SSG(빌드 타임, 최속) · ISR(N초마다 재생성, 절충) · SSR(매 요청, 최신). Next 15 기본은 SSR(no-store), 명시적으로 force-cache·revalidate 설정. 사용자별·실시간은 SSR, 분단위는 ISR, 안 변하면 SSG. 페이지마다·fetch 마다 다르게 줘서 비용/신선도 최적. 다음 편에서 캐싱의 네 가지 층위를 한 번에 정리한다.

다음 편 예고 — Next.js 캐싱 완전 정리

Request Memoization·Data Cache·Full Route·Router Cache 4층. 17편.

© 2026 주나이테크(주) @JUNAITECH