시간을 기다릴 수 없는 변경이 있어
시간 기반 ISR만 쓰면 편집자가 글을 고친 뒤에도 재검증 창이 끝날 때까지 옛 내용을 볼 수 있어. 요청형 재검증은 변경이 성공한 바로 그 순간 관련 캐시를 무효화해. 데이터 변경과 화면 갱신을 하나의 흐름으로 묶는 거야.
| 함수 | 무효화 범위 |
|---|---|
revalidatePath(path, type?) | 특정 경로. 'page'는 해당 잎만, 'layout'은 그 아래까지 포함해. |
revalidateTag(tag) | fetch(..., { next: { tags } })로 같은 태그를 붙인 모든 요청을 찾아. |
경로와 태그의 관점이 달라
경로 무효화는 “이 화면을 다시 만들어라”에 가깝고, 태그 무효화는 “이 데이터에 기대는 모든 화면을 새로 읽어라”에 가까워. 같은 글이 목록과 상세 화면에 함께 나온다면 태그가 중복 경로를 나열하는 것보다 안전해.
변경이 일어나는 자리에서만 호출해
두 함수는 서버 액션과 라우트 핸들러에서 호출해야 해. Next.js 15는 렌더링 도중 호출하면 오류를 내. 캐시 무효화는 데이터 변경의 부수 효과이지, 같은 입력으로 같은 UI를 만들어야 하는 순수 렌더링의 책임이 아니기 때문이야.
변경 작업마다 어떤 읽기 결과가 영향을 받는지 데이터 이름으로 적어. 글 하나를 고치면 상세·목록·작성자 페이지가 함께 바뀔 수 있으니 공통 post:<id>와 목록 태그를 설계해. 무효화는 DB 쓰기가 성공한 뒤에만 실행하고, 실패했을 때 캐시만 먼저 지우지 않게 해.
큰 태그 하나로 모든 콘텐츠를 무효화하면 구현은 쉬워도 작은 변경마다 전체 캐시가 사라져. 반대로 ID 태그만 쓰면 목록 집계가 오래될 수 있어. 데이터 의존 그래프를 반영한 몇 개의 안정된 태그가 경로를 끝없이 나열하는 것보다 오래 살아. 한 글을 목록·상세·작성자 화면에서 공유하고 path와 tag 무효화를 각각 적용해 봐. 변경 직후 세 화면이 언제 새 값을 읽는지 비교하고, 렌더 도중 함수를 호출했을 때 Next.js 15가 오류를 내는지도 테스트로 고정해.
삭제와 생성도 같은 태그 정책을 거쳐야 해. 수정만 시험하면 목록에 새 항목이 안 나타나거나 삭제한 상세가 캐시에 남는 구멍을 놓쳐. 데이터 수명 주기의 모든 변경을 한 무효화 표에 넣어.