Nextjs를 하면서 그렇게 손에 꼽아온 기능, 웹 성능 최적화의 새로운 패러다임인 Next.js의 PPR (Partial Prerendering) 을 실제 부하 테스트를 통해 검증해 보았습니다. 동일한 로직을 가진 두 애플리케이션을 대상으로, PPR 적용 유무에 따라 사용자 경험과 서버 부하가 어떻게 달라지는지 확인했습니다.
해당 기능은 정말 개발하는 동안 계속해서 기다려온 기능중 하나입니다. 단순히 다이나믹한 화면을 보여주는건 기존 Nextjs에서도 Suspense를 활용하여 구현이 가능했습니다.
다만 회사에서 진행하는 프로젝트는 초당 리퀘스트가 수십개가 꽂힐 경우 시피유 사용률과 메모리 사용률이 기하급수적으로 상승했기때문에 이 문제를 해결 할 필요가 있었고 그 대안으로 해당 기능을 생각해왔으며 실제로 Nextjs16이 오픈된 이후 실제 성능 테스트를 진행 해 볼 예정입니다.
기존 Next.js 렌더링 방식은 크게 두 가지로 나뉘었습니다.
PPR은 이 두 가지의 장점을 결합한 하이브리드 방식입니다.
즉, "일단 껍데기(Shell)부터 0.1초 만에 보여주고, 알맹이(내용)는 천천히 채운다" 는 전략입니다.
PPR의 효과를 극명하게 확인하기 위해 다음과 같은 비교군을 설정했습니다.
| 구분 | 폴더명 | 설명 | 비고 |
|---|---|---|---|
| PPR 적용 (Compare) | compare | 정적 셸 + 동적 컴포넌트 스트리밍 | 응답 속도 최적화 기대 |
| PPR 미적용 (Target) | target | 일반적인 Dynamic Rendering | 모든 요청을 서버에서 처리 |
Dashboard 컴포넌트를 Suspense로 감싸 배치했습니다.k6를 사용하여 점진적으로 2,000 VUs(가상 유저)까지 트래픽을 증가시켰습니다.http_req_duration(요청 처리 시간), p(95)(상위 95% 느린 요청의 응답 속도).Nextjs를 하면서 그렇게 손에 꼽아온 기능, 웹 성능 최적화의 새로운 패러다임인 Next.js의 PPR (Partial Prerendering) 을 실제 부하 테스트를 통해 검증해 보았습니다. 동일한 로직을 가진 두 애플리케이션을 대상으로, PPR 적용 유무에 따라 사용자 경험과 서버 부하가 어떻게 달라지는지 확인했습니다.
해당 기능은 정말 개발하는 동안 계속해서 기다려온 기능중 하나입니다. 단순히 다이나믹한 화면을 보여주는건 기존 Nextjs에서도 Suspense를 활용하여 구현이 가능했습니다.
다만 회사에서 진행하는 프로젝트는 초당 리퀘스트가 수십개가 꽂힐 경우 시피유 사용률과 메모리 사용률이 기하급수적으로 상승했기때문에 이 문제를 해결 할 필요가 있었고 그 대안으로 해당 기능을 생각해왔으며 실제로 Nextjs16이 오픈된 이후 실제 성능 테스트를 진행 해 볼 예정입니다.
기존 Next.js 렌더링 방식은 크게 두 가지로 나뉘었습니다.
PPR은 이 두 가지의 장점을 결합한 하이브리드 방식입니다.
즉, "일단 껍데기(Shell)부터 0.1초 만에 보여주고, 알맹이(내용)는 천천히 채운다" 는 전략입니다.
PPR의 효과를 극명하게 확인하기 위해 다음과 같은 비교군을 설정했습니다.
| 구분 | 폴더명 | 설명 | 비고 |
|---|---|---|---|
| PPR 적용 (Compare) | compare | 정적 셸 + 동적 컴포넌트 스트리밍 | 응답 속도 최적화 기대 |
| PPR 미적용 (Target) | target | 일반적인 Dynamic Rendering | 모든 요청을 서버에서 처리 |
Dashboard 컴포넌트를 Suspense로 감싸 배치했습니다.k6를 사용하여 점진적으로 2,000 VUs(가상 유저)까지 트래픽을 증가시켰습니다.http_req_duration(요청 처리 시간), p(95)(상위 95% 느린 요청의 응답 속도).PPR 적용 (Compare) 폴더에서는 config 설정에 cacheComponents: true 옵션을 활성화 시켰고
PPR 미적용 (Target) 폴더는 cacheComponents: true 옵션을 활성화 하지 않았습니다
추가로 다이나믹한 환경울 구현하기 위해서 msw를 이용해서 mock API 서버를 구현해두었습니다
두 프로젝트를 빌드 할 경우 아래와 같이 실제로 적용여부가 나타납니다


테스트 결과는 놀라울 정도로 극명한 차이를 보여주었습니다.
| 지표 | PPR 적용 (Compare) ✅ | PPR 미적용 (Target) ❌ | 차이 |
|---|---|---|---|
| 평균 응답 시간 (Avg) | 0.23초 (231ms) | 4.83초 | 약 20배 차이 |
| p(75) | 0.25초 | 3.81초 (SLA 초과 🚨) | - |
| p(95) | 1.06초 | 21.54초 | 심각한 지연 |
Threshold 결과:
COMPARE: ✓ 패스 (254ms < 1500ms)TARGET: ✗ 실패 (3.81s > 1500ms)
[유튜브영상]
PPR의 압도적인 초기 응답:
Compare 그룹은 평균 231ms라는 매우 빠른 응답 속도를 기록했습니다. 이는 동적 데이터(Dashboard)가 준비되지 않았더라도, 정적 셸(Header, Layout)을 즉시 반환했기 때문입니다. 사용자는 "로딩 중" 상태를 바로 볼 수 있어 체감 성능이 뛰어납니다.
서버 부하와 병목 현상:
Target 그룹은 트래픽이 몰리자 응답 시간이 급격히 치솟아 최대 31초까지 지연되었습니다. 모든 요청마다 전체 HTML을 새로 그리느라 Node.js 서버의 이벤트 루프가 막히고, 이로 인해 단순한 페이지 요청조차 처리가 늦어진 것입니다. 반면 Compare는 정적 자원을 효율적으로 서빙하여 서버 리소스를 동적 연산에만 집중할 수 있었습니다.
이번 실험을 통해 **PPR(Partial Prerendering)**이 단순한 성능 개선을 넘어, 대규모 트래픽 상황에서의 서비스 안정성을 확보하는 데 핵심적인 역할을 한다는 것을 확인했습니다.
Next.js를 사용한 고성능 웹 서비스 구축을 고려한다면, PPR은 선택이 아닌 필수적인 선택이 될겁니다!

위 사진은 PPR 을 활성화 시킨 compare 프로젝트에서 정상적으로 cpu와 memory 사용률이 집계가 안되는 이슈가 존재합니다
어떠한 이유로 인해 PPR 을 활성화 시킨 프로젝트는 단순히 일반적인 Nextjs와 다른 방식으로 cpu와 메모리를 수집해야 되는데 이부분은 전문 분야가 아니라서, AI 도움을 받아 전역상태의 ? 무엇인가를 만들어 수집률을 저장했습니다.