본문 바로가기
C.W.K.
Stream
Lesson 03 of 09 · published

시간 기반 재검증과 ISR

~20 min · ISR, revalidate, stale-while-revalidate

Level 0호기심
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

정적 속도와 충분히 새로운 데이터를 함께 얻어

시간 기반 재검증은 App Router의 ISR 방식이야. 페이지를 미리 렌더링해 캐시에서 빠르게 제공하되, 정해 둔 시간이 지나면 다음 요청이 백그라운드 갱신을 시작해. 그 요청을 보낸 사용자는 새 렌더링을 기다리지 않고 기존 캐시를 즉시 받아.

요청 하나와 라우트 전체 중 범위를 골라

범위설정
특정 fetch()fetch(url, { next: { revalidate: 60 } })
페이지나 레이아웃 구간export const revalidate = 60

수명 주기를 순서대로 보자

처음 요청은 렌더링한 결과를 캐시에 넣어. 재검증 시간 안의 요청은 그 결과를 곧바로 받아. 시간이 지난 뒤 첫 요청은 오래된 결과를 받으면서 백그라운드 갱신을 시작하고, 갱신이 끝난 다음 요청부터 새 결과를 받아. 그래서 사용자는 “새 콘텐츠를 만드는 중”이라는 spinner를 보지 않아.

초 단위 숫자는 제품 요구에서 나와야 해

재검증 간격이 짧을수록 새롭지만 계산량이 늘고, 길수록 싸지만 오래된 값을 보여 줄 가능성이 커져. 가격, 글, 재고처럼 데이터 종류마다 허용 가능한 지연을 먼저 정해.

재검증 간격은 콘텐츠 생산 주기보다 사용자에게 허용되는 지연으로 정해. 하루 한 번 편집해도 게시 직후 바로 보여야 한다면 긴 ISR과 요청형 무효화를 함께 쓸 수 있어. 캐시 응답의 나이와 백그라운드 갱신 실패를 관측해야 숫자가 실제로 지켜지는지도 알 수 있어.

ISR은 정확히 N초마다 자동 새로 만드는 cron이 아니야. 시간이 지난 뒤 들어온 다음 요청이 갱신을 시작하므로 트래픽이 없으면 새 결과도 만들어지지 않아. 정해진 시각에 반드시 갱신해야 하는 데이터는 별도 작업이나 webhook이 필요해. 짧은 재검증 간격을 설정하고 창 안과 밖에서 여러 번 요청해 stale 응답과 백그라운드 갱신 순서를 기록해. 창이 지나도 요청이 없으면 새 결과가 생기지 않는다는 점을 확인하고, 갱신이 실패했을 때 이전 캐시가 어떻게 제공되는지도 시험해. 재검증 중 동시에 여러 요청이 들어왔을 때 갱신 작업이 중복되는지도 관측해. 플랫폼과 배포 형태에 따라 캐시 공유 범위가 다르므로 개발 서버에서 본 한 번의 동작을 전 세계 production의 보장으로 확대하면 안 돼.

Code

fetch별 ISR·tsx
export default async function ProductPage({ params }: { params: Promise<{ id: string }> }) {
  const { id } = await params;
  const res = await fetch(`https://api.example.com/products/${id}`, {
    next: { revalidate: 60 },
  });
  return <ProductCard product={await res.json()} />;
}
구간별 ISR·tsx
// app/blog/page.tsx
export const revalidate = 300;

export default async function BlogPage() {
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return <PostList posts={posts} />;
}
라우트의 렌더링 방식을 강제로 지정하기·tsx
// app/(marketing)/page.tsx
export const dynamic = 'force-static';   // 한 번 빌드하고 다시 렌더링하지 않아

// app/(app)/dashboard/page.tsx
export const dynamic = 'force-dynamic';  // 요청마다 렌더링

External links

Exercise

ISR 상품 페이지에 짧은 간격을 두고 첫 요청, 간격 안의 요청, 간격 뒤 첫·두 번째 요청을 실행해 stale 응답과 백그라운드 갱신 순서를 기록해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.