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 사용