Post

Next.js (9. Revalidating) 정리

Next.js (9. Revalidating) 정리

0. 재검증


재검증(Revalidation)은 캐시된 데이터를 최신 상태로 갱신하는 과정이다.
빠른 캐시 응답을 유지하면서도 콘텐츠를 최신 상태로 유지할 수 있다.

두 가지 전략이 있다:

  • 시간 기반 재검증
    • cacheLife를 사용해 설정한 주기마다 자동으로 캐시를 갱신한다.
  • 온디맨드 재검증
    • 데이터 변경 후 revalidateTag, updateTag, revalidatePath로 수동으로 캐시를 무효화한다.

1. cacheLife — 캐시 수명 설정


cacheLife캐시된 데이터의 유효 기간을 제어한다. use cache 스코프 안에서 호출해 캐시 수명을 설정한다.

1
2
3
4
5
6
7
8
9
// app/lib/data.ts

import { cacheLife } from 'next/cache'

export async function getProducts() {
  'use cache'
  cacheLife('hours')
  return db.query('SELECT * FROM products')
}

1-1. 프로파일 종류


cacheLife에 프로파일 이름을 문자열로 전달해 미리 정의된 캐시 수명을 적용한다.

프로파일stalerevalidateexpire
seconds01초60초
minutes5분1분1시간
hours5분1시간1일
days5분1일1주
weeks5분1주30일
max5분30일거의 무제한

seconds 프로파일이나 revalidate: 0, 또는 expire가 5분 미만이면 단기 캐시로 분류된다.
단기 캐시는 프리렌더링에서 자동으로 제외되고 동적 처리 영역이 된다.

cacheLife의 3가지 시간 기준 (stale / revalidate / expire)

항목stalerevalidateexpire
의미데이터가 “오래됨”으로 간주되는 시점데이터를 “다시 가져오기 시작하는” 시점캐시가 “완전히 만료되는” 시점
동작 방식캐시 그대로 사용기존 캐시 보여주면서 백그라운드에서 fetch캐시 사용 불가 → 무조건 새 fetch
사용자 입장빠르게 보여짐빠름 + 점진적 최신화느릴 수 있음
한 줄 요약오래됐지만 계속 사용 가능쓰면서 뒤에서 업데이트이제는 반드시 새로 가져와야 함

1-2. 커스텀 설정


세밀한 제어가 필요하면 객체를 직접 전달해 각 항목을 개별 설정한다.

1
2
3
4
5
6
'use cache'
cacheLife({
  stale: 3600,    // 1시간 동안 stale로 간주
  revalidate: 7200, // 2시간마다 재검증
  expire: 86400,  // 1일 후 만료
})

2. cacheTag — 캐시 태깅


cacheTag는 캐시된 데이터에 태그를 붙여 온디맨드 재검증의 대상으로 만든다. use cache 스코프 안에서 호출한다.

1
2
3
4
5
6
7
8
9
// app/lib/data.ts

import { cacheTag } from 'next/cache'

export async function getProducts() {
  'use cache'
  cacheTag('products')
  return db.query('SELECT * FROM products')
}

태그를 붙인 후 revalidateTag 또는 updateTag로 해당 캐시를 무효화한다.
여러 함수에 동일한 태그를 사용하면 한 번에 모두 재검증할 수 있다.

3. 온디맨드 재검증 API


3-1. revalidateTag — stale-while-revalidate


revalidateTag는 태그로 캐시 항목을 무효화하되, stale-while-revalidate 방식으로 동작한다.

만료된 콘텐츠를 즉시 제공하면서 백그라운드에서 새 콘텐츠를 생성한다. 블로그 포스트나 상품 목록처럼 약간의 업데이트 지연이 허용되는 콘텐츠에 적합하다.

1
2
3
4
5
6
7
8
// app/lib/actions.ts

import { revalidateTag } from 'next/cache'

export async function updateUser(id: string) {
  // 데이터 변경
  revalidateTag('user', 'max') // 권장: stale-while-revalidate
}

두 번째 인자는 백그라운드에서 새 콘텐츠가 생성되는 동안 만료된 콘텐츠를 얼마나 오래 제공할지를 설정한다. 'max'를 사용하면 가장 긴 stale 허용 시간이 적용된다. Server Action과 Route Handler 모두에서 호출할 수 있다.

3-2. updateTag — 즉시 만료


updateTag는 캐시를 즉시 만료시켜 사용자가 자신의 변경 사항을 바로 확인할 수 있게 한다. revalidateTag와 달리 Server Action에서만 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// app/lib/actions.ts

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}`)
}
 updateTagrevalidateTag
사용 위치Server Action 전용Server Action + Route Handler
동작 방식즉시 만료stale-while-revalidate
사용 사례사용자가 자신의 변경 사항을 바로 확인백그라운드 갱신 (약간의 지연 허용)

3-3. revalidatePath — 경로 기반 재검증


revalidatePath는 특정 경로의 모든 캐시를 무효화한다. 어떤 태그가 연결되어 있는지 알 수 없을 때 사용한다.

1
2
3
4
5
6
7
8
// app/lib/actions.ts

import { revalidatePath } from 'next/cache'

export async function updateUser(id: string) {
  // 데이터 변경
  revalidatePath('/profile')
}

태그 기반 재검증(revalidateTag/updateTag)이 가능하다면 경로 기반보다 태그 기반을 우선한다.
태그 기반이 더 정밀하고 불필요한 캐시 무효화를 방지한다.

4. 캐싱 전략 가이드


런타임 데이터에 의존하지 않고 일정 기간 캐시에서 제공해도 괜찮은 데이터에 캐싱을 적용한다. use cachecacheLife를 함께 사용해 캐시 동작을 명시적으로 설정한다.

CMS(Content Management System)처럼 업데이트 메커니즘이 있는 콘텐츠는 캐시 수명을 길게 설정하고, 실제로 변경이 발생할 때 revalidateTag로 갱신하는 방식이 더 효율적이다.

This post is licensed under CC BY 4.0 by the author.