재검증(Revalidating)
재검증(Revalidating)
재검증(revalidation)은 캐시된 데이터를 갱신하는 과정이에요. 캐시된 응답을 계속 빠르게 제공하면서도 콘텐츠가 신선하게 유지되게 해 주죠. Next.js에는 크게 두 가지 전략이 있어요. 정해진 시간 후 자동 갱신하는 시간 기반(time-based)과, 어떤 변경 뒤 수동으로 무효화하는 온디맨드(on-demand) 방식이에요.
출처: https://nextjs.org/docs/app/getting-started/revalidating
두 가지 재검증 전략
- 시간 기반 재검증 —
cacheLife를 써서 정해진 시간이 지나면 캐시된 데이터를 자동으로 새로고침해요. - 온디맨드 재검증 — 변경(뮤테이션) 후
revalidateTag,updateTag,revalidatePath로 캐시된 데이터를 수동으로 무효화해요.
cacheLife
cacheLife는 캐시된 데이터가 얼마나 오래 유효한지를 정해요. use cache 스코프 안에서 사용해요.
import { cacheLife } from 'next/cache'
export async function getProducts() {
'use cache'
cacheLife('hours')
return db.query('SELECT * FROM products')
}
cacheLife는 프로파일 이름이나 커스텀 설정 객체를 받아요.
| 프로파일 | stale |
revalidate |
expire |
|---|---|---|---|
default |
5m | 15m | never |
seconds |
30s | 1s | 60s |
minutes |
5m | 1m | 1h |
hours |
5m | 1h | 1d |
days |
5m | 1d | 1w |
weeks |
5m | 1w | 30d |
max |
5m | 30d | 1y |
세밀한 제어가 필요하면 객체를 넘겨요.
'use cache'
cacheLife({
stale: 3600, // 1시간 후 stale 로 간주
revalidate: 7200, // 2시간 후 재검증
expire: 86400, // 1일 후 만료
})
seconds 프로파일, revalidate: 0, 또는 expire가 5분 미만이면 캐시는 "단기 수명"으로 간주돼요. 단기 수명 캐시는 자동으로 프리렌더에서 제외되고 대신 동적 홀이 돼요.
cacheTag
cacheTag는 캐시된 데이터에 태그를 붙여서 온디맨드로 무효화할 수 있게 해줘요.
import { cacheTag } from 'next/cache'
export async function getProducts() {
'use cache'
cacheTag('products')
return db.query('SELECT * FROM products')
}
태그가 붙으면 revalidateTag나 updateTag로 캐시를 무효화할 수 있어요.
revalidateTag
revalidateTag는 stale-while-revalidate 시맨틱으로 태그 캐시를 무효화해요 — 신선한 콘텐츠가 백그라운드에서 로드되는 동안 옛 콘텐츠를 즉시 제공해요. 블로그 글·상품 카탈로그처럼 갱신에 약간의 지연이 허용되는 콘텐츠에 적합해요.
import { revalidateTag } from 'next/cache'
export async function updateUser(id: string) {
// 데이터 변경
revalidateTag('user', 'max') // 권장: stale-while-revalidate
}
같은 태그를 여러 함수에 재사용해 한 번에 모두 재검증할 수 있어요. revalidateTag는 Server Action이나 Route Handler에서 호출해요. 두 번째 인자는 신선한 콘텐츠가 생성되는 동안 옛 콘텐츠를 얼마나 오래 서빙할지 정해요. 'max'를 쓰면 가장 긴 stale 창을 줘요.
updateTag
updateTag는 read-your-own-writes 시나리오를 위해 캐시된 데이터를 즉시 만료시켜요 — 사용자가 옛 콘텐츠 대신 자신의 변경을 바로 볼 수 있게 해요. revalidateTag와 달리 Server Actions에서만 사용할 수 있어요.
updateTag |
revalidateTag |
|
|---|---|---|
| 위치 | Server Actions 전용 | Server Actions와 Route Handlers |
| 동작 | 캐시 즉시 만료 | Stale-while-revalidate |
| 용도 | Read-your-own-writes (사용자가 자신의 변경을 봄) | 백그라운드 새로고침 (약간의 지연 허용) |
import { updateTag } from 'next/cache'
import { redirect } from 'next/navigation'
export async function createPost(formData: FormData) {
const post = await db.post.create({
data: {
title: formData.get('title'),
content: formData.get('content'),
},
})
updateTag('posts')
redirect(`/posts/${post.id}`)
}
revalidatePath
revalidatePath는 특정 라우트 경로의 모든 캐시된 데이터를 무효화해요. 어떤 태그가 연관됐는지 모르는 채 라우트를 재검증하고 싶을 때 써요.
import { revalidatePath } from 'next/cache'
export async function updateUser(id: string) {
// 데이터 변경
revalidatePath('/profile')
}
가능하면 태그 기반 재검증(revalidateTag/updateTag)을 경로 기반보다 선호해요. 더 정밀하고 과잉 무효화를 피할 수 있어요.
무엇을 캐시해야 하나
런타임 데이터에 의존하지 않고, 한동안 캐시에서 서빙해도 괜찮은 데이터를 캐시해요. use cache와 cacheLife로 그 동작을 표현하면 돼요. 시간 기반 재검증이 필요 없는 콘텐츠(CMS 데이터 등)는 cacheTag와 긴 cacheLife(예: max)를 써서 정적 셸에 유지하고, 콘텐츠가 바뀌면 웹훅 등으로 revalidateTag를 호출하게 설정해요.
더 알아보기
- Caching: https://nextjs.org/docs/app/getting-started/caching
cacheLifeAPI 레퍼런스: https://nextjs.org/docs/app/api-reference/functions/cacheLiferevalidateTagAPI 레퍼런스: https://nextjs.org/docs/app/api-reference/functions/revalidateTag