최근 회사 프로젝트를 Next.js 13 Pages Router에서 Next.js 15 App Router로 마이그레이션하는 작업을 완료했습니다.
약 3개월간의 마이그레이션 과정에서 겪은 경험과 SSR/CSR 성능 차이를 실제 데이터와 함께 공유하고자 합니다.
마이그레이션을 결정한 이유
기존 Pages Router 기반의 프로젝트는 약 50개의 페이지와 다양한 API 라우트를 포함하고 있었습니다.
Next.js 15 App Router로의 마이그레이션을 결정한 주요 이유는 다음과 같습니다.
성능 개선 기대
- React Server Components의 도입으로 번들 크기 감소
- 향상된 데이터 페칭 패턴
- 개선된 라우팅 성능
개발자 경험(DX) 향상
- 파일 기반 라우팅의 직관성
- 레이아웃 중첩 기능
- 스트리밍과 Suspense의 원활한 통합
마이그레이션 과정에서 마주한 주요 도전과제
폴더 구조 재구성
Pages Router의 pages/
디렉토리를 App Router의 app/
디렉토리로 변경하는 작업이 첫 번째 과제였습니다.
기존 구조:
pages/
index.js
about.js
products/
[id].js
새로운 구조:
app/
page.js
about/
page.js
products/
[id]/
page.js
데이터 페칭 패턴 변경
getServerSideProps
와 getStaticProps
를 Server Components의 직접적인 데이터 페칭으로 변경하는 과정에서 가장 많은 시간이 소요되었습니다.
기존 방식:
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
새로운 방식:
async function Page() {
const data = await fetchData();
return <div>{data}</div>;
}
클라이언트 컴포넌트 분리
Next.js 15 App Router에서는 'use client' 지시어를 통해 클라이언트 컴포넌트를 명시적으로 구분해야 합니다.
상태 관리나 이벤트 핸들러가 필요한 컴포넌트들을 식별하고 적절히 분리하는 작업이 필요했습니다.
SSR vs CSR 성능 비교 실측 데이터
마이그레이션 완료 후 동일한 페이지에서 SSR과 CSR 성능을 비교 측정했습니다.
테스트 환경
- 대상 페이지: 상품 상세 페이지 (약 20개 컴포넌트 포함)
- 데이터 소스: API 호출 3개 (상품 정보, 리뷰, 관련 상품)
- 측정 도구: Lighthouse, Chrome DevTools
- 네트워크: Fast 3G, Regular 3G 환경
핵심 성능 지표 비교
First Contentful Paint (FCP)
SSR이 CSR 대비 약 50% 빠른 FCP 성능을 보였습니다.
SSR 결과:
- Fast 3G: 0.8초
- Regular 3G: 1.4초
CSR 결과:
- Fast 3G: 1.6초
- Regular 3G: 2.8초
Largest Contentful Paint (LCP)
LCP에서도 SSR이 현저히 우수한 성능을 나타냈습니다.
SSR 결과:
- Fast 3G: 1.2초
- Regular 3G: 2.1초
CSR 결과:
- Fast 3G: 2.4초
- Regular 3G: 4.2초
Time to Interactive (TTI)
SSR 결과:
- Fast 3G: 2.1초
- Regular 3G: 3.8초
CSR 결과:
- Fast 3G: 3.2초
- Regular 3G: 5.6초
번들 크기 비교
마이그레이션 후 JavaScript 번들 크기가 약 30% 감소했습니다.
- 마이그레이션 전: 245KB (gzipped)
- 마이그레이션 후: 171KB (gzipped)
종합 성능 비교표
성능 지표 | SSR (App Router) | CSR (Pages Router) | 개선율 |
---|---|---|---|
FCP - Fast 3G | 0.8초 | 1.6초 | 50% ↑ |
FCP - Regular 3G | 1.4초 | 2.8초 | 50% ↑ |
LCP - Fast 3G | 1.2초 | 2.4초 | 50% ↑ |
LCP - Regular 3G | 2.1초 | 4.2초 | 50% ↑ |
TTI - Fast 3G | 2.1초 | 3.2초 | 34% ↑ |
TTI - Regular 3G | 3.8초 | 5.6초 | 32% ↑ |
번들 크기 | 171KB | 245KB | 30% ↓ |
초기 JavaScript | 85KB | 180KB | 53% ↓ |
Next.js 15 App Router 후기: 장점과 단점
기능별 상세 비교표
기능 | Pages Router | App Router | 평가 |
---|---|---|---|
라우팅 | 파일 기반 방식 | 폴더 기반 방식 | ⭐⭐⭐⭐⭐ |
데이터 페칭 | getServerSideProps 방식 | Server Components 직접 호출 | ⭐⭐⭐⭐⭐ |
레이아웃 | _app.js, _document.js | 중첩 레이아웃 지원 | ⭐⭐⭐⭐⭐ |
스트리밍 | 제한적 지원 | 네이티브 지원 | ⭐⭐⭐⭐⭐ |
번들 크기 | 상대적으로 큰 편 | Server Components로 최적화 | ⭐⭐⭐⭐⭐ |
학습 곡선 | 상대적으로 쉬움 | 초기 학습 필요 | ⭐⭐⭐ |
호환성 | 완전 호환 | 일부 라이브러리 대응 필요 | ⭐⭐⭐⭐ |
디버깅 | 상대적으로 쉬움 | 서버/클라이언트 구분 필요 | ⭐⭐⭐ |
장점
1. 향상된 성능
React Server Components 덕분에 클라이언트로 전송되는 JavaScript 양이 현저히 줄어들었습니다.
특히 데이터 페칭이 많은 페이지에서 성능 향상이 두드러졌습니다.
2. 개선된 개발자 경험
중첩 레이아웃과 스트리밍 기능으로 복잡한 UI를 더 직관적으로 구현할 수 있게 되었습니다.
3. SEO 최적화
서버에서 완전히 렌더링된 HTML을 제공하여 검색 엔진 최적화에 유리합니다.
단점
1. 학습 곡선
Server Components와 Client Components의 경계를 이해하는 데 시간이 필요합니다.
2. 디버깅 복잡성
서버와 클라이언트 간의 경계가 모호할 때 디버깅이 까다로울 수 있습니다.
3. 생태계 호환성
일부 라이브러리가 아직 App Router를 완전히 지원하지 않는 경우가 있습니다.
마이그레이션 팁과 베스트 프랙티스
점진적 마이그레이션 전략
전체 프로젝트를 한 번에 마이그레이션하는 대신 페이지별로 점진적으로 진행하는 것을 권장합니다.
Next.js는 Pages Router와 App Router의 공존을 지원하므로 안전한 마이그레이션이 가능합니다.
컴포넌트 분리 기준
다음 기준에 따라 Server Component와 Client Component를 구분했습니다:
구분 | Server Component | Client Component |
---|---|---|
주요 용도 | 데이터 페칭, 정적 렌더링 | 상호작용, 상태 관리 |
적용 대상 | 데이터 페칭 위주 컴포넌트 | React hooks 사용 컴포넌트 |
성능 특성 | 번들 크기 감소 | 높은 상호작용성 |
SEO 효과 | 우수함 | 제한적 |
로딩 속도 | 빠름 | 보통 |
Server Component 적용 사례:
- 블로그 포스트 목록 페이지
- 상품 카탈로그 화면
- 정적 콘텐츠 영역
Client Component 적용 사례:
- 검색 필터 컴포넌트
- 장바구니 기능
- 실시간 채팅 위젯
성능 모니터링
마이그레이션 후 지속적인 성능 모니터링이 중요합니다.
Vercel Analytics나 Google PageSpeed Insights를 활용하여 정기적으로 성능을 체크하고 있습니다.
실제 사용자 경험 개선 사례
전자상거래 상품 페이지
상품 상세 페이지에서 SSR을 적용한 결과, 검색 엔진 노출이 20% 증가했습니다.
또한 초기 로딩 시간 단축으로 이탈률이 15% 감소하는 효과를 얻었습니다.
블로그 포스트 페이지
정적 콘텐츠가 주를 이루는 블로그 페이지에서는 Static Site Generation(SSG)을 활용했습니다.
빌드 시점에 페이지를 미리 생성하여 CDN을 통한 빠른 콘텐츠 제공이 가능해졌습니다.
마이그레이션 후 메트릭 개선 결과
Core Web Vitals 개선
Cumulative Layout Shift (CLS):
- 마이그레이션 전: 0.15
- 마이그레이션 후: 0.08
First Input Delay (FID):
- 마이그레이션 전: 85ms
- 마이그레이션 후: 45ms
마이그레이션 전후 상세 비교표
측정 항목 | 마이그레이션 전 | 마이그레이션 후 | 개선율 |
---|---|---|---|
CLS | 0.15 | 0.08 | 47% ↑ |
FID | 85ms | 45ms | 47% ↑ |
LCP | 2.4초 | 1.2초 | 50% ↑ |
로딩 속도 만족도 | 68% | 84% | 16%p ↑ |
사용자 경험 만족도 | 72% | 88% | 16%p ↑ |
페이지 이탈률 | 35% | 20% | 15%p ↓ |
검색 엔진 노출 | 기준값 | +20% | 20% ↑ |
평균 세션 시간 | 2분 15초 | 3분 40초 | 63% ↑ |
사용자 만족도 지표
사용자 설문조사 결과:
- 페이지 로딩 속도 만족도: 68% → 84%
- 전반적인 사용자 경험 만족도: 72% → 88%
향후 계획과 지속적인 최적화
Progressive Enhancement 적용
기본적인 기능은 JavaScript 없이도 작동하도록 하고, JavaScript가 로드된 후 향상된 경험을 제공하는 방식을 적용할 예정입니다.
Edge Runtime 활용
API 라우트에 Edge Runtime을 적용하여 전 세계 사용자에게 더 빠른 응답 시간을 제공할 계획입니다.
모니터링 체계 강화
Real User Monitoring (RUM)을 도입하여 실제 사용자 경험을 지속적으로 측정하고 개선할 예정입니다.
결론
Next.js 15 App Router로의 마이그레이션은 초기 학습 비용이 있었지만, 성능과 개발자 경험 측면에서 명확한 이점을 제공했습니다.
특히 SSR을 통한 초기 로딩 성능 개선과 SEO 최적화 효과가 두드러졌습니다.
하지만 CSR이 항상 나쁜 선택은 아닙니다.
사용자 상호작용이 많은 대시보드나 SPA 형태의 애플리케이션에서는 CSR이 더 적합할 수 있습니다.
중요한 것은 프로젝트의 특성과 요구사항에 맞는 렌더링 전략을 선택하는 것입니다.
Next.js 15 App Router는 SSR, CSR, SSG를 모두 지원하므로 페이지별로 최적의 렌더링 방식을 선택할 수 있다는 것이 가장 큰 장점이라고 생각합니다.
앞으로도 지속적인 성능 모니터링과 최적화를 통해 더 나은 사용자 경험을 제공하도록 노력하겠습니다.
'프론트엔드' 카테고리의 다른 글
프론트엔드 개발자를 위한 최신 Lint/Formatter 세팅 가이드 2025 (0) | 2025.06.24 |
---|---|
HTMX로 서버사이드 렌더링 현대화하기 - SPA 없는 동적 웹 (0) | 2025.06.23 |
Solid.js 시작하기 - React보다 빠른 리액티브 프레임워크 (0) | 2025.06.22 |
Playwright로 E2E 테스트 자동화 - Selenium 대체 완벽 가이드 2025 (0) | 2025.06.20 |
Flutter vs React Native 2025 - 크로스플랫폼 개발 선택 가이드 (0) | 2025.06.19 |