Next.js 15에서는 Partial Prerendering (PPR) 이라는 새로운 렌더링 방식이 도입되었다.

PPR은 기존의 Static Site Generation (SSG)Server-Side Rendering (SSR) 의 장점을 결합하여,

“가능한 부분은 정적으로 미리 렌더링하고, 나머지는 서버에서 동적으로 제공하는 방식”을 지원한다.

그렇다면 PPR이 기존 SSG, SSR과 어떻게 다른지, 그리고 실무에서 어떻게 활용할 수 있는지 살펴보자.


1. 기존 SSG vs SSR의 한계

Next.js는 기존에 SSG(Static Site Generation) 또는 SSR(Server-Side Rendering) 중 하나를 선택해야 했다.

SSG (Static Site Generation)

페이지를 빌드 시점에 정적으로 생성

빠른 로딩 속도 제공 (CDN 활용 가능)

단점: 실시간 데이터를 반영하기 어렵고, 업데이트가 필요한 경우 전체 페이지를 다시 빌드해야 함

export async function getStaticProps() {
  const data = await fetch("https://api.example.com/data").then((res) => res.json());

  return { props: { data } };
}

SSR (Server-Side Rendering)

페이지 요청 시마다 서버에서 데이터를 가져와 렌더링

최신 데이터를 항상 반영할 수 있음

단점: 매 요청마다 서버에서 페이지를 생성해야 하므로 속도가 느려질 수 있음

export async function getServerSideProps() {
  const data = await fetch("https://api.example.com/data").then((res) => res.json());

  return { props: { data } };
}

2. PPR(Partial Prerendering)이란?

PPR은 SSG와 SSR을 혼합하는 새로운 방식이다.

즉, 가능한 부분은 미리 렌더링하고, 실시간 데이터가 필요한 부분만 동적으로 제공하는 방식이다.

PPR의 핵심 개념

정적인 부분은 미리 생성 (SSG 방식 유지)

동적인 데이터는 서버에서 제공 (SSR처럼 실시간 처리 가능)

요청할 때마다 전체 페이지를 새로 생성할 필요 없음

빠른 로딩 속도를 유지하면서도 최신 데이터 반영 가능


3. PPR 적용 방식 (App Router vs Page Router)

PPR은 App Router와 Page Router 모두에서 사용할 수 있지만, 적용 방식이 다르다.

📌 App Router에서 PPR 적용 예제

export const dynamic = "auto"; // PPR 활성화

export default async function Page() {
  const staticData = await fetch("https://api.example.com/static-data", { cache: "force-cache" }).then((res) => res.json());
  const dynamicData = await fetch("https://api.example.com/dynamic-data", { cache: "no-store" }).then((res) => res.json());

  return (
    <div>
      <h1>정적 데이터: {staticData.title}</h1>
      <h2>실시간 데이터: {dynamicData.value}</h2>
    </div>
  );
}

📌 코드 설명

• staticData: cache: “force-cache” → 빌드 시 캐싱된 데이터를 반환 (정적 콘텐츠)

• dynamicData: cache: “no-store” → 매 요청마다 새 데이터를 가져옴 (동적 콘텐츠)

• export const dynamic = “auto”; → PPR을 활성화하여 필요한 경우만 동적 데이터 요청

💡 이제 fetch()만으로도 PPR을 쉽게 구현할 수 있다.


📌 Page Router에서 PPR 적용 예제

Page Router에서는 초기 페이지를 SSG로 미리 렌더링한 후, 클라이언트 측에서 데이터를 가져오는 방식을 사용해야 한다.

import useSWR from "swr";

const fetcher = (url) => fetch(url).then((res) => res.json());

export async function getStaticProps() {
  const staticData = await fetcher("https://api.example.com/static-data");

  return { props: { staticData } };
}

export default function Page({ staticData }) {
  const { data: dynamicData } = useSWR("/api/dynamic-data", fetcher, { refreshInterval: 5000 });

  return (
    <div>
      <h1>정적 데이터: {staticData.title}</h1>
      <h2>실시간 데이터: {dynamicData ? dynamicData.value : "불러오는 중..."}</h2>
    </div>
  );
}

📌 코드 설명

• getStaticProps() → 정적 데이터를 빌드 시점에 미리 가져옴 (SSG)

• useSWR() → 클라이언트 측에서 주기적으로 새로운 데이터를 가져옴

💡 즉, Page Router에서 PPR과 같은 효과를 내려면 SSR을 혼합하는 것이 아니라, 클라이언트에서 데이터를 주기적으로 갱신해야 한다.


4. 기존 SSG, SSR과의 차이점

SSG (Static)SSR (Dynamic)PPR (Hybrid)
빌드 시 정적 페이지 생성✅ 가능❌ 불가능✅ 부분적으로 가능
실시간 데이터 반영❌ 불가능✅ 가능✅ 가능 (필요한 부분만)
초기 로딩 속도✅ 매우 빠름❌ 상대적으로 느림✅ 빠름 (정적 데이터 활용)
CDN 캐싱 활용✅ 가능❌ 불가능✅ 가능 (정적 부분)
서버 부하✅ 낮음❌ 높음🔄 중간 (정적 + 동적 조합)

💡 PPR을 활용하면, 초기 로딩 속도를 유지하면서도 SSR처럼 최신 데이터를 반영할 수 있다.


5. PPR을 사용해야 하는 경우

정적인 콘텐츠(예: 블로그, 문서)는 빠르게 로딩하면서, 최신 데이터(예: 댓글, 조회수)는 실시간으로 반영하고 싶을 때

SEO가 중요한 페이지지만, 일부 동적 콘텐츠가 필요할 때

SSR을 사용하면 속도가 너무 느려지고, SSG만 사용하면 최신 데이터를 반영하기 어려울 때

PPR을 고려하지 않아도 되는 경우

완전히 정적인 사이트 (정적 사이트 생성만으로 충분한 경우)

실시간 데이터가 필요 없는 페이지


6. 결론 – PPR을 어떻게 활용해야 할까?

정적 페이지(SSG)와 동적 데이터(SSR)를 조합할 수 있다.

초기 로딩 속도를 빠르게 유지하면서도, 최신 데이터 반영이 가능하다.

CDN 캐싱을 활용할 수 있어 서버 부하를 줄일 수 있다.

Next.js 15 이후로 점점 더 많이 활용될 가능성이 크다.

PPR을 잘 활용하면 SSR의 단점(느린 속도)과 SSG의 단점(데이터 갱신 어려움)을 동시에 해결할 수 있다.


최종 정리

“초기 로딩 속도는 유지하면서, 일부 데이터는 최신 상태로 유지하고 싶다”PPR 사용

“완전히 정적인 사이트를 만들고 싶다”기존 SSG 유지

“실시간 데이터가 중요한 페이지다”SSR 또는 React Query 사용