본문 바로가기
Frontend2026년 5월 1일6분 읽기

Next.js 16 캐싱 모델 — "use cache" 디렉티브 실전 정리

YS
김영삼
조회 645
Next.js 16 캐싱 모델 — "use cache" 디렉티브 실전 정리

핵심 요약

Next.js 16(2026-04 릴리스)은 캐싱 모델을 명시적(opt-in)으로 전환했다. 14·15의 "기본 캐싱"이 혼란을 만들었다는 인식에서 출발했다. 디폴트는 모두 동적, 캐시는 'use cache' 또는 cache()로 명시.

1. 새 디렉티브 — 'use cache'

// 컴포넌트 자체를 캐시
'use cache'
export default async function Header() {
  const config = await fetch('https://api.example.com/header').then(r => r.json())
  return <nav>{config.title}</nav>
}

함수 단위 캐시도 가능:

async function getProducts(category: string) {
  'use cache'
  return db.product.findMany({ where: { category } })
}

2. cacheLife / cacheTag — 갱신 제어

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

async function getProduct(id: string) {
  'use cache'
  cacheLife('hours')          // 'minutes' | 'hours' | 'days' | 'weeks' | 'max'
  cacheTag('product', `product-${id}`)
  return db.product.findUnique({ where: { id } })
}

// 변경 시 무효화
import { revalidateTag } from 'next/cache'
revalidateTag(`product-${productId}`)

3. fetch 캐시 — 더 이상 자동 아님

버전fetch 디폴트변경
13.4 ~ 14.xforce-cacheSSG 친화
15.xno-store (예외 많음)혼란
16.x완전 동적명시적 opt-in 필수
// 16.x — 명시적 캐시
const data = await fetch('https://api.example.com/data', {
  cache: 'force-cache',
  next: { revalidate: 3600 },
})

4. dynamicIO 모드

실험적이지만 권장. 빌드 시점에 동적·정적 경계를 컴파일러가 분석.

// next.config.js
module.exports = {
  experimental: { dynamicIO: true },
}

장점: 런타임 오류로 빠지던 케이스가 빌드 타임에 잡힘. cookies()·headers()를 캐시된 영역에서 호출하면 빌드 실패.

5. 페이지·라우트 단위 제어

// app/page.tsx
export const dynamic = 'force-static'  // 페이지 전체 정적
export const revalidate = 60           // ISR 60초

// 동적으로 강제
export const dynamic = 'force-dynamic'

6. 마이그레이션 — 14/15 → 16

  1. 1단계: npx @next/codemod@latest upgrade
  2. 2단계: 빌드 시 "Detected dynamic API in cached scope" 에러 모두 수정
  3. 3단계: 핫 페이지(트래픽 큰 페이지)부터 'use cache' 적용 — Vercel Speed Insights로 효과 측정
  4. 4단계: dynamicIO 활성화 → 잠재 버그 박멸
  5. 5단계: 기존 fetch 호출 옵션 점검

7. 흔한 함정

  • 'use cache' + cookies(): 빌드 실패. 쿠키는 캐시될 수 없음.
  • 중첩 캐시: 부모만 캐시되면 자식 컴포넌트의 동적 데이터가 stale. 자식도 명시적 캐시.
  • revalidateTag: 빌드된 라우트만 갱신. 동적 라우트는 다음 요청 시 자동 처리.
  • development와 production 차이: 개발 모드에서는 'use cache'도 매 요청 실행. 운영 동작 검증은 next start 필수.

8. 성능 측정

# 빌드 출력에서 라우트별 타입 확인
$ next build
Route (app)                    Size     First Load JS
○ /                            142 B    87.2 kB
ƒ /products/[id]               198 B    91.4 kB
●  /blog/[slug]                612 B    93.8 kB

○  Static    ●  ISR    ƒ  Dynamic

9. 실전 가이드 — 결정 트리

  • "매 요청마다 데이터가 다른가?" → 캐시 안 함 (디폴트)
  • "분당 1회 이내 변경?" → 'use cache' + cacheLife('minutes')
  • "콘텐츠가 거의 안 바뀜?" → force-static + revalidateTag로 갱신
  • "사용자별로 다름?" → cookies/headers 사용 → 자동 동적

참고 자료

  • Next.js 공식 문서 /docs/app/building-your-application/caching
  • Vercel 블로그 "From caching to use cache" — 2026-04-15

댓글 0

아직 댓글이 없습니다.
Ctrl+Enter로 등록