Published on

Next.js 16 완벽 가이드 - 새로운 기능과 주요 변경사항 총정리

목차

들어가며

2025년 10월, Next.js 16이 정식 릴리즈되었다. 이번 메이저 버전은 Turbopack의 안정화, 혁신적인 캐싱 시스템, AI 기반 디버깅 도구 등 대규모 변경사항을 포함하고 있다.

이 글에서는 Next.js 16의 모든 주요 기능과 Breaking Changes를 상세히 다룬다.

1. Turbopack: 이제 기본 번들러로

성능 혁신

Turbopack이 모든 새 Next.js 프로젝트의 기본 번들러가 되었다:

  • Fast Refresh: 최대 10배 향상
  • 프로덕션 빌드: 2-5배 빠른 빌드 속도
  • 파일 시스템 캐싱: 재시작 시 더 빠른 컴파일 (베타)

마이그레이션

기존 webpack 설정이 있다면 플래그로 우회 가능:

# 개발
next dev --webpack

# 프로덕션
next build --webpack

파일 시스템 캐싱 활성화

next.config.ts
const nextConfig = {
  experimental: {
    turbopackFileSystemCacheForDev: true,
  },
}

export default nextConfig

2. Cache Components와 "use cache" 지시어

명시적 캐싱 모델

Next.js 16은 opt-in 캐싱 모델을 도입한다. 이전과 달리 동적 코드는 기본적으로 요청마다 실행된다.

활성화 방법

next.config.ts
const nextConfig = {
  cacheComponents: true,
}

export default nextConfig

"use cache" 지시어 사용

app/blog/[slug]/page.tsx
import { cacheLife } from 'next/cache'

export default async function BlogPost({ params }) {
  'use cache'
  cacheLife('days')

  const { slug } = await params
  const post = await fetchBlogPost(slug)

  return <article>{post.content}</article>
}

컴파일러가 자동으로 캐시 키를 생성하며, Partial Pre-Rendering(PPR)과 통합되어 혼합 렌더링이 가능하다.


3. cacheLife 프로필

내장 프로필

Next.js 16은 7가지 내장 프로필을 제공한다:

프로필용도stalerevalidateexpire
default표준 콘텐츠5분15분1년
seconds실시간 데이터30초1초1분
minutes빈번한 업데이트5분1분1시간
hours하루 중 여러 번 업데이트5분1시간1일
days일일 업데이트5분1일1주
weeks주간 업데이트5분1주30일
max거의 변하지 않는 콘텐츠5분30일1년

커스텀 프로필 정의

next.config.ts
const nextConfig = {
  cacheComponents: true,
  cacheLife: {
    blog: {
      stale: 3600,      // 1시간
      revalidate: 900,  // 15분
      expire: 86400,    // 1일
    },
    biweekly: {
      stale: 60 * 60 * 24 * 14,  // 14일
      revalidate: 60 * 60 * 24,   // 1일
      expire: 60 * 60 * 24 * 14,  // 14일
    },
  },
}

export default nextConfig

인라인 프로필 사용

'use cache';
import { cacheLife } from 'next/cache';

export default async function Page() {
  cacheLife({
    stale: 3600,
    revalidate: 900,
    expire: 86400,
  });

  return <div>Page</div>;
}

cacheTag와 조합

import { cacheLife, cacheTag } from 'next/cache';

async function getPostContent(slug: string) {
  'use cache';

  const post = await fetchPost(slug);
  cacheTag(`post-${slug}`);

  if (!post) {
    cacheLife('minutes');
    return null;
  }

  cacheLife('days');
  return post.data;
}

4. 새로운 캐싱 API

revalidateTag() - Stale-While-Revalidate

이제 cacheLife 프로필을 두 번째 인수로 필수로 받는다:

import { revalidateTag } from 'next/cache';

// ✅ 추천
revalidateTag('blog-posts', 'max');

// 다른 내장 프로필
revalidateTag('news-feed', 'hours');
revalidateTag('analytics', 'days');

// 커스텀 시간
revalidateTag('products', { expire: 3600 });

특징: 사용자는 캐시된 데이터를 즉시 받고, 백그라운드에서 새로고침된다.

사용 시점: 정적 콘텐츠로 최종 일관성(eventual consistency)을 허용할 수 있을 때


updateTag() - Read-Your-Writes

Server Actions 전용으로 즉시 새로고침을 제공한다:

'use server';

import { updateTag } from 'next/cache';

export async function updateUserProfile(userId: string, profile: Profile) {
  await db.users.update(userId, profile);

  // 캐시 만료 및 즉시 새로고침
  updateTag(`user-${userId}`);
}

특징: 동일 요청 내에서 캐시를 만료하고 즉시 최신 데이터를 읽는다.

사용 시점: 폼 제출, 사용자 설정 등 즉시 피드백이 필요한 상호작용


refresh() - 캐시 무관 데이터 새로고침

Server Actions 전용으로 캐시되지 않은 데이터만 새로고친다:

'use server';

import { refresh } from 'next/cache';

export async function markNotificationAsRead(notificationId: string) {
  await db.notifications.markAsRead(notificationId);

  // 캐시하지 않은 데이터만 새로고침
  refresh();
}

용도: 알림 수, 실시간 지표 같은 캐시되지 않은 동적 데이터 갱신


5. proxy.ts - middleware.ts의 새로운 이름

변경 사항

middleware.tsproxy.ts로 이름이 변경되었다:

proxy.ts
import { NextRequest, NextResponse } from 'next/server'

export default function proxy(request: NextRequest) {
  return NextResponse.redirect(new URL('/home', request.url))
}

export const config = {
  matcher: '/about/:path*',
}

주요 차이점

  • 파일명: middleware.tsproxy.ts
  • 함수명: middlewareproxy
  • 목적: 애플리케이션의 네트워크 경계를 명확하게 표현
  • 런타임: Node.js 런타임에서만 실행

middleware.ts는 여전히 Edge 런타임용으로 지원되지만 deprecated되었다.


6. Next.js DevTools MCP

AI 기반 디버깅

Model Context Protocol(MCP) 통합으로 AI가 개발 워크플로우 내에서 문제를 진단한다:

주요 기능:

  • Next.js 지식: 라우팅, 캐싱, 렌더링 동작 이해
  • 통합 로그: 브라우저와 서버 로그를 한 곳에서 확인
  • 자동 오류 접근: 스택 추적을 수동으로 복사할 필요 없음
  • 페이지 인식: 현재 라우트 컨텍스트 이해

AI 에이전트가 직접 애플리케이션 컨텍스트를 활용해 설명과 해결책을 제공한다.


7. React Compiler 안정화

활성화 방법

next.config.ts
const nextConfig = {
  reactCompiler: true,
}

export default nextConfig
npm install babel-plugin-react-compiler@latest

주요 기능

  • 컴포넌트를 자동으로 메모이제이션
  • 불필요한 리렌더링 감소

주의사항

  • 기본적으로 활성화되지 않음 (성능 데이터 수집 중)
  • Babel 의존성으로 인해 개발/빌드 시간 증가 가능

8. Enhanced Routing & Navigation

Layout Deduplication

50개의 상품 링크가 있는 페이지에서 레이아웃을 1번만 다운로드한다 (이전: 50번).

Incremental Prefetching

  • 캐시에 없는 부분만 미리 로드
  • 뷰포트를 벗어나면 요청 취소
  • 호버/재진입 시 우선순위 부여
  • 캐시 무효화 시 자동 재미리로드

트레이드오프: 더 많은 개별 prefetch 요청이 발생할 수 있지만, 총 전송 크기는 훨씬 낮다.


9. Breaking Changes

필수 버전 요구사항

요구사항이전Next.js 16
Node.js18+20.9+ (LTS)
TypeScript4.5+5.1+
브라우저Chrome 108+Chrome 111+, Edge 111+, Firefox 111+, Safari 16.4+

제거된 기능

제거됨대체 방법
AMP 지원완전 제거
next lintBiome/ESLint 직접 사용
serverRuntimeConfig, publicRuntimeConfig환경 변수 (.env)
devIndicators 설정 옵션제거됨
experimental.pprCache Components로 통합
experimental.dynamicIOcacheComponents로 재명명
unstable_rootParams()대안 개발 중
자동 scroll-behavior: smooth제거됨

next lint 마이그레이션

npx @next/codemod@canary next-lint-to-eslint-cli .

비동기 Props 필수화

모든 동적 props가 비동기로 변경되었다:

// ❌ Next.js 15
export default function Page({ params, searchParams }) {
  const { slug } = params;
  const { query } = searchParams;
}

// ✅ Next.js 16
export default async function Page({ params, searchParams }) {
  const { slug } = await params;
  const { query } = await searchParams;
}

동일하게 적용:

// 모두 await 필요
const cookieStore = await cookies();
const headersList = await headers();
const { isEnabled } = await draftMode();

next/image 기본값 변경

설정이전Next.js 16
minimumCacheTTL60초4시간 (14400초)
imageSizes[16, 32, 48, ...][32, 48, ...] (16 제거)
qualities[1-100][75] (이제 필수 설정)
dangerouslyAllowLocalIP허용기본 차단 (보안 강화)
maximumRedirects무제한3으로 제한 (보안 강화)

중요: qualities는 이제 필수 설정이며, 설정하지 않으면 악의적인 사용자가 의도하지 않은 품질 최적화를 요청할 수 있다.


Parallel Routes: default.js 필수

모든 슬롯에 명시적인 default.js 파일이 필요하다:

app/@modal/default.tsx
export default function Default() {
  return null
  // 또는 notFound()
}

없으면 404 에러가 발생한다.


revalidateTag() 시그니처 변경

// ❌ 구식
revalidateTag('blog-posts');

// ✅ SWR 동작
revalidateTag('blog-posts', 'max');

// ✅ 즉시 업데이트 필요 시
import { updateTag } from 'next/cache';
updateTag('user-id');

10. 추가 개선사항

로깅 강화

개발 요청과 빌드에서 시간 소비를 상세히 표시:

GET /dashboard 200 in 1.2s
  Compile: 450ms
  Render: 750ms

병렬 실행

next devnext build를 동시에 실행할 수 있도록 출력 디렉토리 분리

Lockfile

동일 프로젝트의 중복 인스턴스 방지

Sass

sass-loader v16으로 현대 문법 지원


11. 마이그레이션 가이드

자동 업그레이드 (권장)

npx @next/codemod@canary upgrade latest

자동으로 다음을 처리한다:

  • 패키지 버전 업그레이드
  • Breaking changes 수정
  • 설정 파일 업데이트

수동 업그레이드

npm install next@latest react@latest react-dom@latest

이후 Breaking Changes를 수동으로 수정:

  1. 비동기 props 변환: params, searchParams, cookies(), headers(), draftMode()await 추가
  2. revalidateTag() 수정: 두 번째 인자로 cacheLife 프로필 추가
  3. Parallel routes: 모든 슬롯에 default.js 추가
  4. middleware.ts 이름 변경: proxy.ts로 변경 (선택사항)
  5. Node.js 20.9+ 업그레이드
  6. TypeScript 5.1+ 업그레이드

12. 실전 예시

블로그 포스트 캐싱

app/blog/[slug]/page.tsx
import { cacheLife, cacheTag } from 'next/cache'

export default async function BlogPost({ params }) {
  'use cache'

  const { slug } = await params
  const post = await fetchPost(slug)

  cacheTag(`post-${slug}`)

  if (!post) {
    cacheLife('minutes') // 404는 짧게 캐싱
    return notFound()
  }

  cacheLife('days') // 정상 포스트는 일일 갱신
  return <article>{post.content}</article>
}

사용자 프로필 업데이트

app/actions.ts
'use server'

import { updateTag } from 'next/cache'

export async function updateProfile(userId: string, data: ProfileData) {
  await db.users.update(userId, data)

  // 즉시 UI 반영
  updateTag(`user-${userId}`)
}

실시간 알림 카운트

app/actions.ts
'use server'

import { refresh } from 'next/cache'

export async function markAsRead(notificationId: string) {
  await db.notifications.markAsRead(notificationId)

  // 캐시되지 않은 알림 수만 새로고침
  refresh()
}

마치며

Next.js 16은 성능, 개발자 경험, 캐싱 제어에서 큰 발전을 이뤘다:

  • Turbopack 안정화로 10배 빠른 개발 경험
  • 명시적 캐싱 모델로 예측 가능한 동작
  • AI 기반 디버깅으로 문제 해결 시간 단축

다만 Breaking Changes가 많으므로 마이그레이션 시 충분한 테스트가 필요하다. 자동 codemod를 활용하면 대부분의 변경사항을 안전하게 처리할 수 있다.

참고 자료