핵심 요약
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.x | force-cache | SSG 친화 |
| 15.x | no-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단계:
npx @next/codemod@latest upgrade - 2단계: 빌드 시 "Detected dynamic API in cached scope" 에러 모두 수정
- 3단계: 핫 페이지(트래픽 큰 페이지)부터
'use cache'적용 — Vercel Speed Insights로 효과 측정 - 4단계:
dynamicIO활성화 → 잠재 버그 박멸 - 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