Ch 05. 정기적으로 새로 굽다 — ISR
매일 아침 새로 굽는 빵
앞 챕터에서 빵을 미리 구워두는 SSG를 이야기했습니다. 그런데 빵집에 문제가 생겼습니다. 새벽 네 시에 구운 빵이 오후 세 시까지도 그대로 있습니다. 아침에 구운 빵은 맛있었지만, 시간이 지날수록 신선함이 떨어집니다.
이 문제를 해결하는 방법이 있습니다. 매일 아침, 그리고 점심에 한 번 더, 저녁에도 한 번 — 정기적으로 빵을 새로 굽는 겁니다. 손님에게는 항상 최근에 구운 빵을 드릴 수 있습니다.
ISR(Incremental Static Regeneration)이 이런 방식입니다. 처음에는 SSG처럼 빌드 시점에 HTML을 만들지만, 설정한 시간이 지나면 백그라운드에서 조용히 페이지를 새로 생성합니다.
revalidate 옵션으로 정기 재생성
ISR을 활성화하는 방법은 간단합니다. fetch에 next: { revalidate: 초 } 옵션을 추가하거나, 페이지 파일에 export const revalidate = 초를 선언합니다.
// 파일: app/posts/page.tsx
// 이 페이지는 1시간(3600초)마다 새로 생성됩니다.
export const revalidate = 3600;
interface Post {
id: number;
title: string;
excerpt: string;
publishedAt: string;
}
async function getPosts(): Promise<Post[]> {
const res = await fetch('https://api.example.com/posts', {
next: { revalidate: 3600 }, // 3600초마다 재검증
});
return res.json();
}
export default async function PostsPage() {
const posts = await getPosts();
return (
<main>
<h1>블로그</h1>
<ul>
{posts.map((post) => (
<li key={post.id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<time>{post.publishedAt}</time>
</li>
))}
</ul>
</main>
);
}
```text
`revalidate: 3600`이면, 마지막으로 페이지를 생성한 지 1시간이 지난 후 첫 번째 요청이 오면 백그라운드에서 새 페이지를 생성하기 시작합니다. 그 사이 요청에는 이전에 만들어진 페이지를 계속 내려줍니다. 새 페이지 생성이 완료되면, 이후 요청부터 새 페이지를 받습니다.
### On-demand Revalidation — 원할 때 즉시 갱신
시간 기반 ISR의 한계는 최대 `revalidate` 초만큼 오래된 데이터가 보일 수 있다는 점입니다. 게시글을 방금 수정했는데 사용자에게는 1시간 후에나 반영된다면 불편합니다.
Next.js는 이를 해결하기 위해 **On-demand Revalidation**을 제공합니다. 특정 이벤트가 발생했을 때(게시글 저장, 댓글 작성 등) 캐시를 즉시 무효화할 수 있습니다.
```tsx
// 파일: app/api/revalidate/route.ts
import { revalidatePath } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get('secret');
// 비밀 토큰 검증
if (secret !== process.env.REVALIDATE_SECRET) {
return NextResponse.json({ error: '권한 없음' }, { status: 401 });
}
const path = searchParams.get('path') ?? '/posts';
revalidatePath(path);
return NextResponse.json({ revalidated: true, path });
}
이 API를 CMS나 웹훅에서 호출하면, 해당 경로의 캐시가 즉시 무효화됩니다. 다음 요청에서는 새로운 페이지가 생성됩니다.
SSG와의 차이
SSG는 빌드 이후에는 절대 변하지 않습니다. 새 배포를 해야만 반영됩니다. ISR은 빌드 이후에도 정해진 주기로, 또는 필요할 때 즉시 페이지를 새로 만들 수 있습니다.
| 구분 | SSG | ISR |
|---|---|---|
| 최초 생성 | 빌드 시점 | 빌드 시점 |
| 이후 갱신 | 재배포 필요 | 자동 (주기적) 또는 수동 트리거 |
| 실시간성 | 없음 | 제한적 있음 |
| 서버 부하 | 없음 | 매우 낮음 |
다음 챕터에서는
다음 챕터에서는 네 가지 렌더링 방식을 한눈에 비교하고, 실무에서 어떤 페이지에 어떤 방식을 쓸지 결정하는 가이드를 정리합니다. 블로그 글 목록은 SSG가 맞을까요, ISR이 맞을까요? 답을 함께 찾아봅니다.