Next.js 15 완벽 가이드 - React 19 지원 및 새로운 기능
웹 개발의 동향은 빠르게 변하고 있습니다. 특히 Next.js 15의 릴리즈는 React 19 RC 지원과 함께 개발자 경험을 크게 향상시키는 여러 혁신적 기능들을 가져왔습니다. 이 글에서는 Next.js 15의 핵심 기능들을 자세히 살펴보고, 기존 프로젝트를 어떻게 업그레이드할 수 있는지 알아봅시다.
React 19 RC와 React Compiler 소개
Next.js 15는 React 19 RC(Release Candidate)를 완벽하게 지원합니다. 이는 단순한 버전 업그레이드를 넘어 개발 경험의 질적 변화를 의미합니다.
React Compiler란?
React Compiler는 Meta의 React 팀이 개발한 새로운 실험적 컴파일러로, 가장 흥미로운 기능 중 하나입니다.
// React Compiler 없이: 수동으로 메모이제이션 필요
import { useMemo, useCallback } from 'react';
export function UserProfile({ userId }) {
const userData = useMemo(() => {
return fetchUserData(userId);
}, [userId]);
const handleUpdate = useCallback(() => {
updateUser(userData);
}, [userData]);
return <div>{userData.name}</div>;
}
// React Compiler 사용: 자동 최적화
export function UserProfile({ userId }) {
const userData = fetchUserData(userId);
const handleUpdate = () => updateUser(userData);
return <div>{userData.name}</div>;
}
React Compiler는 다음과 같은 이점을 제공합니다:
- 자동 메모이제이션:
useMemo,useCallback코드를 자동으로 최적화 - 코드 간결성: 반복적인 최적화 코드 제거
- 성능 개선: 불필요한 리렌더링 자동 방지
- 디버깅 용이: 더 깔끔한 코드로 문제 추적 간편
하이드레이션(Hydration) 오류 개선
Next.js 15에서는 클라이언트-서버 간 불일치로 인한 하이드레이션 오류를 더 명확하게 처리합니다. 오류 메시지가 구체적으로 어느 부분에서 문제가 발생했는지 정확하게 안내합니다.
캐싱 동작의 중요한 변경점
Next.js 15에서는 캐싱의 기본값이 변경되어 더 예측 가능한 성능을 제공합니다.
변경된 캐싱 규칙
| 요청 타입 | 이전 동작 | Next.js 15 동작 |
| fetch() 요청 | 기본 캐싱됨 | 캐싱되지 않음 |
| GET 라우트 핸들러 | 기본 캐싱됨 | 캐싱되지 않음 |
| 클라이언트 네비게이션 | 부분 캐싱 | 캐싱되지 않음 |
// Next.js 15에서 명시적 캐싱 설정 필요
import { NextResponse } from 'next/server';
export async function GET(request: Request) {
const data = await fetch('https://api.example.com/data', {
next: { revalidate: 60 } // 60초마다 재검증
});
return NextResponse.json(data);
}
이 변경은:
- 예측 가능성: 개발자가 의도적으로 캐시 전략 결정
- 성능 최적화: 필요한 경우만 캐싱하여 메모리 효율성 향상
- 데이터 신선도: 실시간 데이터가 필요한 경우 자동 반영
Partial Prerendering (PPR): 하이브리드 렌더링
Partial Prerendering은 정적 콘텐츠와 동적 콘텐츠를 효과적으로 조합하는 새로운 렌더링 전략입니다.
PPR의 동작 원리
// app/products/[id]/page.tsx
import { Suspense } from 'react';
export const experimental_ppr = true; // PPR 활성화
async function ProductHeader({ id }: { id: string }) {
const product = await getProduct(id);
return <h1>{product.name}</h1>;
}
function ProductReviews({ id }: { id: string }) {
// 동적으로 로드되는 리뷰 섹션
return <ReviewSection productId={id} />;
}
export default function ProductPage({ params }: { params: { id: string } }) {
return (
<div>
<ProductHeader id={params.id} />
<Suspense fallback={<div>리뷰 로딩 중...</div>}>
<ProductReviews id={params.id} />
</Suspense>
</div>
);
}
PPR의 장점
- 빠른 초기 로딩: 정적 부분을 미리 렌더링
- 동적 콘텐츠 지원: Suspense로 동적 데이터 처리
- SEO 최적화: 정적 콘텐츠는 검색 엔진이 즉시 인덱싱
- 유연한 아키텍처: 페이지의 각 섹션별로 렌더링 전략 결정
개발 환경 개선: Turbopack 통합
Next.js 15에서는 개발 서버의 빌드 성능을 획기적으로 향상시키는 Turbopack 지원을 강화했습니다.
Turbopack 활성화
# 프로젝트 생성 시 Turbopack 선택
npx create-next-app@latest my-app --turbo
# 기존 프로젝트에 Turbopack 추가
# 1. next.config.js 수정
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
turbopack: true
}
}
module.exports = nextConfig
# 2. 개발 서버 실행 (자동으로 Turbopack 사용)
npm run dev
Turbopack의 성능 개선
- 더 빠른 번들링: Webpack 대비 700배 이상의 성능 향상
- 즉각적인 HMR: 변경사항이 바로 반영되는 개발 경험
- 메모리 효율: 대규모 프로젝트에서도 안정적인 성능
라우트 핸들러와 응답 스트리밍
Next.js 15에서는 응답 스트리밍 후 코드 실행을 위한 새로운 API가 추가되었습니다.
// app/api/process/route.ts
export async function POST(request: Request) {
const data = await request.json();
// 응답 스트리밍 시작
const response = new Response(
new ReadableStream({
async start(controller) {
// 데이터 처리 및 스트리밍
const result = await processData(data);
controller.enqueue(JSON.stringify(result));
controller.close();
}
}),
{
headers: {
'Content-Type': 'application/json',
'Transfer-Encoding': 'chunked'
}
}
);
// 응답 전송 후 추가 작업
response.waitUntil(logProcessing(data, new Date()));
return response;
}
이 기능은:
- 장시간 작업: 백그라운드에서 처리 가능
- 사용자 경험: 응답을 빠르게 반환하고 처리는 이후 진행
- 효율적 리소스: 서버 자원을 효과적으로 활용
패키지 번들링 최적화
Next.js 15에서는 패키지 번들링 전략이 개선되어 앱 크기를 더 효율적으로 관리할 수 있습니다.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// 앱 라우터에서는 외부 패키지가 기본으로 번들링됨
bundledPackages: ['date-fns', 'lodash-es'],
// 특정 패키지는 번들링에서 제외
experimental: {
esmExternals: true
}
}
module.exports = nextConfig
// 페이지 라우터에서의 기존 방식
const nextConfig = {
transpilePackages: ['ui-components', 'shared-utils']
}
Next.js 14에서 15로 업그레이드
기존 프로젝트를 Next.js 15로 업그레이드할 때의 주의사항입니다.
1단계: 의존성 업데이트
npm install next@latest react@latest react-dom@latest
2단계: TypeScript 설정 확인
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"jsx": "react-jsx"
}
}
3단계: 점진적 마이그레이션
// 1. 새로운 기능부터 적용
// 2. 기존 코드의 useMemo, useCallback 검토
// 3. PPR 활성화 고려
// pages/users/[id].tsx
export const experimental_ppr = true;
export async function getStaticProps(context) {
// 점진적으로 앱 라우터로 전환
}
4단계: 테스트 및 배포
npm run build
npm run test
npm start
주의사항 및 하위 호환성
- React 19 RC: 아직 정식 버전이 아니므로 프로덕션 환경에서는 주의 필요
- 캐싱 변경: 기존 캐싱에 의존하는 코드는 명시적으로 수정 필요
- 하위 호환성: 페이지 라우터는 계속 지원되지만 앱 라우터로의 전환 권장
결론
Next.js 15는 웹 개발의 미래를 향한 큰 발걸음입니다. React 19 RC 지원, React Compiler의 자동 최적화, PPR을 통한 하이브리드 렌더링 등 혁신적인 기능들이 개발자 경험과 성능을 크게 향상시킵니다.
특히:
- 성능 최적화: React Compiler와 Turbopack으로 자동화된 성능 개선
- 유연한 렌더링: PPR으로 정적/동적 콘텐츠의 최적 조합
- 개발 생산성: 더 간결한 코드와 빠른 피드백
지금이 Next.js 15로 업그레이드를 시작할 좋은 시기입니다. 점진적으로 새로운 기능을 도입하면서 프로젝트를 현대화해보세요.