리액트 기반 풀스택 프레임워크 시장에서 Next.js의 입지는 여전히 독보적이다. 그런데 2024년 10월 21일 정식 공개된 Next.js 15는 단순한 버전 업이 아니라, 프레임워크가 데이터를 다루고 화면을 그리는 방식 자체를 손본 분기점이었다. 비동기로 바뀐 요청 API, “캐시 우선”에서 “비캐시 우선”으로 뒤집힌 기본값, 정식 안정화된 Turbopack, 그리고 React 19 지원까지 — 한 번에 묶인 변화의 폭이 컸다. 이 글은 Next.js 15가 무엇을 바꿨는지 공식 릴리스 노트 기준으로 정리하고, 1년 뒤 등장한 16 버전으로의 전환 포인트까지 함께 짚는다.
왜 지금 Next.js 15를 다시 봐야 하나
이미 Next.js는 2025년 10월 16이 나왔고, 2026년 3월에는 16.2까지 올라왔다(공식 블로그 기준). 그렇다면 “지난” 15를 굳이 정리할 이유가 있을까. 답은 의외로 분명하다. 16이 도입한 Cache Components와 ‘request 시점에 동적 실행’ 기본값은 모두 15가 깔아 둔 토대 위에 서 있기 때문이다. 비동기 요청 API와 캐싱 기본값 전환을 이해하지 못하면 16의 변화도 절반만 이해하게 된다.
또 하나, 많은 실무 프로젝트가 14 또는 15.x에 머물러 있다. 14에서 곧장 16으로 점프하려는 팀이라면 15가 도입한 호환성 깨짐(breaking change)을 반드시 거쳐야 한다. 그래서 15는 “건너뛸 버전”이 아니라 “반드시 통과해야 하는 길목”에 가깝다.
| 버전 | 정식 출시일 | 핵심 변화 |
|---|---|---|
| Next.js 15 | 2024-10-21 | 비동기 요청 API, 캐싱 기본값 전환, Turbopack Dev 안정화, React 19 |
| Next.js 15.5 | 2025-08-18 | Turbopack 빌드 베타, Node.js 미들웨어 안정화, 16 대비 경고 |
| Next.js 16 | 2025-10-21 | Turbopack 기본 번들러, Cache Components, React Compiler 안정화 |
가장 큰 변화 — 비동기 요청 API (Async Request APIs)
15의 변화 중 체감이 가장 큰 것은 요청 데이터 접근 API가 모두 비동기(async) 로 바뀐 점이다. 기존에는 동기적으로 읽던 cookies, headers, draftMode, 그리고 layout.js·page.js·route.js 등의 params와 page.js의 searchParams가 이제 await을 요구한다.
import { cookies } from 'next/headers';
export async function AdminPanel() {
const cookieStore = await cookies(); // 15부터 await 필요
const token = cookieStore.get('token');
// ...
}
공식 설명에 따르면 이 변경의 목적은 단순하다. 서버 렌더링에서 모든 컴포넌트가 요청 데이터에 의존하는 것은 아닌데, 기존 구조는 요청을 무조건 기다린 뒤 렌더링을 시작했다. API를 비동기로 만들면 프레임워크가 “이 컴포넌트는 요청을 기다려야 한다”는 시점을 명확히 알 수 있고, 그만큼 요청 전에 미리 준비할 여지가 생긴다. 말하자면 음식점이 주문을 받기 전에 손질해 둘 재료를 미리 다듬어 놓는 셈이다.
이는 명백한 호환성 깨짐이라, 마이그레이션 부담이 따른다. 다행히 한동안은 동기 접근도 허용되며(개발·프로덕션에서 경고만 표시), Next.js는 자동 변환 도구(codemod)를 제공한다.
npx @next/codemod@canary next-async-request-api .
캐싱 기본값의 대전환 — “캐시 우선”에서 “비캐시 우선”으로
App Router 초기의 캐싱은 “기본적으로 캐시하고 필요하면 끄는” 다소 공격적인 정책이었다. 커뮤니티 피드백을 반영해 Next.js 15는 이 기본값을 뒤집었다. 공식 릴리스 노트에 따르면 fetch 요청, GET 라우트 핸들러, 클라이언트 라우터 캐시가 더 이상 기본으로 캐시되지 않는다.
GET라우트 핸들러: 14에서는 기본 캐시였으나 15에서는 기본 비캐시. 캐시하려면export const dynamic = 'force-static'같은 옵션을 명시해야 한다.- 클라이언트 라우터 캐시: 페이지 세그먼트의
staleTime이 기본0이 됐다. 즉 페이지 이동 시 항상 최신 데이터를 반영한다. 다만 공유 레이아웃 데이터는 다시 가져오지 않고, 뒤로/앞으로 가기는 캐시에서 복원되며,loading.js는 여전히 5분간 캐시된다.
이 변화는 “데이터를 요청하면 신선한 값을 기대한다”는 웹 플랫폼의 상식에 더 가깝다. 동시에 캐시에 의존하던 기존 코드는 동작이 달라질 수 있어, 업그레이드 시 데이터 신선도와 서버 부하를 함께 점검해야 한다. 이전 동작이 필요하면 staleTimes 설정으로 되돌릴 수 있다.
// next.config.ts — 이전 캐시 동작으로 복귀
const nextConfig = {
experimental: {
staleTimes: { dynamic: 30 },
},
};
export default nextConfig;
React 19 지원과 Turbopack Dev 안정화
Next.js 15는 React 19에 맞춰 정렬됐다. App Router는 React 19 RC를 사용하고, 커뮤니티 요청을 반영해 Pages Router는 React 18과의 하위 호환을 유지한다. 덕분에 Pages Router 사용자는 준비가 되면 React 19로 올라갈 수 있다. 단, 공식 문서는 한 앱에서 Pages Router(React 18)와 App Router(React 19)를 동시에 섞는 구성은 타입 불일치 등 예측 불가능한 동작을 부를 수 있어 권장하지 않는다. 메타의 실험적 React Compiler도 이 버전에서 지원되기 시작했다(다만 Babel 플러그인 기반이라 빌드·개발 속도가 느려질 수 있다는 한계가 명시돼 있다).
빌드 도구 쪽에서는 Rust 기반 번들러 Turbopack의 개발 모드(next dev --turbo)가 정식 안정화됐다. Vercel은 자사 대형 앱 vercel.com 기준으로 다음 수치를 공개했다.
- 로컬 서버 시작 최대 76.7% 단축
- Fast Refresh(코드 변경 반영) 최대 96.3% 단축
- 캐시 없는 초기 라우트 컴파일 최대 45.8% 단축
다만 이 시점의 Turbopack은 개발 모드 한정이었고, 프로덕션 빌드(next build)는 여전히 webpack을 썼다는 점은 분명히 짚어 둘 필요가 있다. 프로덕션 빌드의 Turbopack 적용은 뒤에서 다룰 15.5의 몫이었다.
실무에 와닿는 그 밖의 기능들
대형 변화 외에도 일상적인 개발 경험을 끌어올리는 기능이 함께 들어왔다.
<Form>컴포넌트 (next/form): HTML<form>에 프리페치·클라이언트 내비게이션·점진적 향상을 더한다. 검색 폼처럼 결과 페이지로 이동하는 양식에 특히 유용하다.instrumentation.js안정화:register()API로 서버 라이프사이클에 접근해 성능·오류를 관측할 수 있다. Sentry와 협업해onRequestError훅도 추가됐다.next.config.ts지원: 설정 파일을 타입세이프하게 작성하고NextConfig타입으로 자동완성을 받는다.- 서버 액션 보안 강화: 사용되지 않는 서버 액션은 빌드 시 제거(dead code elimination)되고, 클라이언트가 참조하는 액션 ID는 추측 불가능한 값으로 생성된다.
unstable_after(실험적): 응답 스트리밍이 끝난 뒤 로깅·분석 같은 후속 작업을 실행한다.- 정적 라우트 표시기(Static Route Indicator): 개발 중 어떤 라우트가 정적/동적인지 시각적으로 보여 준다.
참고로 이 버전부터 Node.js 최소 요구 버전은 18.18.0으로 올라갔고, ESLint 9 지원도 추가됐다.
Next.js 15에서 16으로 — 지금 준비할 것
2025년 8월 18일 나온 15.5는 16으로 가는 징검다리였다. 프로덕션 Turbopack 빌드(next build --turbopack)가 베타로 공개됐는데, 공식 발표에 따르면 이 빌드는 출시 후 vercel.com·v0.app·nextjs.org에서 누적 12억 건 이상의 요청을 처리하며 검증됐고, 30코어 머신 기준 대형 사이트에서 최대 5배 빠른 빌드를 기록했다. 같은 릴리스에서 Node.js 런타임 미들웨어와 타입 라우트(typed routes)가 안정화됐고, next lint는 폐기 예고됐다.
결정적으로 15.5는 16에서 사라질 기능들에 대한 폐기 경고를 미리 띄웠다. 업그레이드를 앞둔 팀이라면 이 목록을 먼저 점검해야 한다.
| 16에서 변경/제거 | 대응 방법 |
|---|---|
next/link의 legacyBehavior |
prop과 자식 <a> 제거 |
| AMP 지원 전면 제거 | next/amp·amp 설정 제거 |
next/image 기본 quality 75로 제한 |
images.qualities 명시 |
| 로컬 이미지 쿼리스트링 | images.localPatterns 설정 |
동기 params/cookies()/headers() |
await로 전환(15에서 시작된 흐름) |
실제 16(2025-10-21)에서는 Turbopack이 개발·프로덕션 모두에서 기본 번들러가 됐고, use cache 지시어와 PPR을 묶은 Cache Components로 캐싱이 전면 opt-in 모델로 재편됐다. 또한 미들웨어 파일이 proxy.ts로 이름을 바꾸고 Node.js 20.9+가 최소 요구 버전이 됐다. 15에서 “비동기·비캐시 기본값”을 받아들여 둔 프로젝트일수록 이 전환이 매끄럽다는 점이, 앞서 15를 “길목”이라 부른 이유다.
업그레이드 체크리스트
- [ ]
npx @next/codemod@canary upgrade latest로 자동 업그레이드 시도 - [ ] 비동기 API codemod 적용 후 동기 접근 경고가 사라졌는지 확인
- [ ]
GET라우트 핸들러·라우터 캐시 동작 변화로 데이터 신선도 점검 - [ ] React 19 호환성(App Router) 또는 React 18 유지(Pages Router) 결정
- [ ] 개발 모드
--turbo로 전환해 빌드/리프레시 속도 비교 - [ ] 16 폐기 목록(
legacyBehavior·AMP·이미지 설정) 사전 정리
마이그레이션 작업량이 부담스럽다면, 반복적인 코드 치환은 AI 코딩 도구의 도움을 받는 것도 방법이다. itinsights에서 정리한 AI 코딩 에이전트 비교와 Claude Code 워크플로우 패턴이 codemod로 다 잡지 못하는 수동 수정 구간을 줄이는 데 참고가 된다.
정리하며
Next.js 15는 화려한 신규 컴포넌트보다, 프레임워크의 기본 가정을 바꾼 “조용한 대수술”에 가까웠다. 비동기 요청 API와 비캐시 기본값은 당장은 마이그레이션 비용을 요구하지만, 16의 Cache Components와 동적 우선 모델로 이어지는 일관된 방향성의 출발점이다. 14에 머문 팀이라면 16으로 직행하기 전에 15가 도입한 호환성 변화를 먼저 소화하는 편이 안전하다.
여러분의 프로젝트는 지금 어느 버전에 있는가. 그리고 캐싱을 “기본 켜짐”으로 가정한 코드가 얼마나 남아 있는가. 이 두 질문에 답할 수 있다면, 다음 업그레이드는 한결 수월해질 것이다.
본 글의 버전·날짜·기능 설명은 Next.js 공식 릴리스 블로그를 기준으로 작성했으며, 프레임워크 버전과 설정 환경에 따라 동작이 달라질 수 있다.
참고 자료
