1. ISR이란?
ISR(Incremental Static Regeneration)은 증분 정적 재생성이라는 뜻으로, 빌드 시 정적으로 생성된 페이지를 일정 주기로 갱신할 수 있는 기능입니다.
SSG 방식의 정적 페이지는 빠르지만 한 번 생성된 이후에는 업데이트가 어렵다는 단점이 있습니다. 이를 보완하기 위해 Next.js에서는 ISR을 도입해 정적 페이지에도 유통기한을 부여할 수 있게 되었습니다.
SSG 방식으로 설정해두면, 해당 페이지는 빌드 타임에 미리 정적으로 생성됩니다. 이렇게 생성된 페이지는 이후 다시 생성되지 않기 때문에, 언제 페이지를 요청하더라도 항상 동일한 정적 파일이 반환됩니다. 덕분에 빠른 응답 속도를 기대할 수 있지만, 최신 데이터를 반영하기 어렵다는 단점이 있습니다.
하지만 ISR 방식을 사용하면, SSG로 생성된 정적 페이지에 마치 ‘유통기한’을 설정하듯 일정한 갱신 주기를 적용할 수 있습니다. 유통기한이 지나기 전까지는 동일한 페이지를 계속해서 응답하지만, 유통기한이 지나면 Next.js 서버가 백그라운드에서 해당 페이지를 새롭게 정적으로 생성합니다. 이후 요청부터는 이 새로 생성된 페이지가 응답되므로, 일정한 주기로 최신 데이터를 반영할 수 있다는 장점이 있습니다.
그렇다고 해서 ISR이 설정된 시간이 지나자마자 타이머처럼 정확히 페이지를 갱신하는 것은 아닙니다. 예를 들어, 시간의 흐름이 왼쪽에서 오른쪽으로 진행된다고 가정해봅시다. 처음에는 SSG 방식처럼 빌드 타임에 V1 페이지가 생성됩니다. 이후 ISR을 통해 예를 들어 60초 후에 페이지를 다시 생성하도록 설정해두었다면, 60초가 지나기 전까지는 계속해서 V1 페이지가 반환됩니다.
그러다 60초가 지난 시점 이후에 누군가가 페이지에 접속하면, 이 요청에는 여전히 V1 페이지가 반환되지만, 동시에 서버에서는 백그라운드에서 새로운 V2 페이지를 생성하게 됩니다. 이렇게 생성된 V2 페이지는 이후의 요청부터 적용되어, 최신 데이터가 반영된 상태로 사용자에게 보여지게 되는 것입니다.
이처럼 ISR은 일정 시간이 지난 후 정적 페이지를 새롭게 재생성하도록 설정할 수 있기 때문에, 기본적으로는 미리 생성된 페이지를 그대로 반환하여 SSG 방식처럼 빠른 응답 속도를 유지할 수 있습니다. 동시에 주기적으로 페이지를 갱신할 수 있어, SSR처럼 최신 데이터도 반영할 수 있다는 장점도 함께 갖고 있습니다.
즉, SSG의 속도와 SSR의 실시간성이라는 두 가지 장점을 모두 취한, 매우 강력한 렌더링 전략이라고 할 수 있습니다.
2. ISR의 작동 방식
아래 예시처럼 getStaticProps 함수에 revalidate 값을 설정하면 일정 시간 이후 페이지를 갱신할 수 있습니다.
export const getStaticProps = async () => {
console.log("인덱스 페이지");
const [allBooks, recoBooks] = await Promise.all([
fetchBooks(),
fetchRandomBooks()
]);
return {
props: { allBooks, recoBooks },
revalidate: 3, // 3초 간격으로 재생성
};
};
빌드 후 사용자가 페이지를 요청하면, 유통기한(revalidate) 이전에는 기존 V1 페이지가 응답됩니다.
유통기한이 지난 후 첫 요청이 들어오면, 기존 페이지를 응답하면서 백그라운드에서 V2 페이지를 새로 생성합니다. 이후 요청부터는 이 V2 페이지가 제공됩니다.
이 구조 덕분에 속도와 데이터 신선도를 모두 만족시킬 수 있습니다.
3. ISR 설정 방법
1. getStaticProps에 revalidate 값을 설정하기
export const getStaticProps = async () => {
(...)
return {
props: { allBooks, recoBooks },
revalidate: 3, // 3초 간격으로 재생성 🌟
};
};
2. 빌드하기
npm run build
빌드 결과를 보면 인덱스 페이지에 ISR이 3초 간격으로 적용되었다는 것을 확인할 수 있습니다.
3. 앱을 실행하고 브라우저에서 새로고침하며 변경 여부 확인하기
npm run start
이와 같이 해당 브라우저를 계속 새로고침하면 3초 주기로 추천도서가 계속 변경되는 것을 확인할 수 있습니다.
4. ISR의 한계와 고민점
ISR에도 단점은 존재합니다. 특히, 사용자 행동에 따라 데이터가 바뀌는 경우에는 ISR의 시간 기반 접근이 한계가 될 수 있습니다.
예시: 커뮤니티 게시글 페이지
- 게시글 수정 : 페이지 데이터를 업데이트 해야함
- 게시글 삭제 : 페이지를 제거해야함
예를 들어, 게시글 페이지를 60초 주기로 재생성하도록 설정했다고 가정해보겠습니다.
가정 ⓵ 게시글이 60초가 되기 전에 수정되는 경우
이 경우, 수정 전의 내용이 60초 동안 계속 노출됩니다.
즉, 사용자가 접속하는 시점에 따라 최신 정보가 반영되지 않은 페이지를 보게 되는 문제가 생깁니다.
가정 ⓶ 게시글 수정이 24시간 이후에 발생하는 경우
이 경우에는 데이터 신선도에는 큰 문제가 없지만, 60초마다 불필요하게 페이지를 재생성하게 됩니다.
이는 자원 낭비로 이어질 수 있습니다.
이러한 한계 때문에, ISR 대신 SSR(Server-Side Rendering)로 전환하고자 하는 생각이 들 수 있습니다.
하지만 SSR은 매 요청마다 서버에서 페이지를 새로 렌더링하기 때문에
- 응답 속도가 느려질 수 있고
- 동시 접속자가 많아질 경우 서버 부하가 커질 수 있습니다
따라서 정적 페이지 방식이 여전히 유리한 경우가 많습니다.
5. On-Demand ISR이란?
Next.js는 이러한 문제를 해결하기 위해 On-Demand ISR, 즉 주문형 재검증 방식도 제공합니다.
사용자 행동에 따라 데이터가 변경된 시점에 직접 페이지 재생성 요청을 트리거하는 방식입니다.
더이상 시간에 의존하지 않고, 필요할 때만 페이지를 새로 생성할 수 있습니다.
6. On-Demand ISR 구현 방법
⓵ API Route를 만듭니다. (/pages/api/revalidate.ts)
import { NextApiRequest, NextApiResponse } from "next";
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
try {
await res.revalidate("/"); // 인덱스 페이지 재생성
return res.json({ revalidate: true });
} catch (err) {
res.status(500).send("Revalidation Failed");
}
}
이처럼 revalidate API Route를 만들어 두면, 해당 주소(/api/revalidate)로 요청이 들어왔을 때 지정한 경로(/)의 페이지가 즉시 재생성됩니다. 재생성이 성공하면 { revalidate: true } 응답이 반환됩니다.
⓶ 빌드 후 앱을 실행합니다.
npm run build
npm run start
⓷ 브라우저에서 아래 주소로 접속하여 revalidate 요청을 보냅니다.
http://localhost:3000/api/revalidate
- 응답: { revalidate: true }
- 콘솔: “인덱스 페이지” 등의 로그 확인 가능
- 브라우저에서 인덱스 페이지 새로고침 시 변경된 데이터가 반영되어 있음을 확인 가능
7. ISR, 왜 강력한가?
Next.js의 ISR은 다음 세 가지 렌더링 전략의 장점을 모두 담고 있습니다.
- SSG의 빠른 응답 속도
- SSR의 최신 데이터 반영
- ISR의 유연한 재생성 주기 조절
또한, On-Demand ISR을 통해 실시간성과 정확성까지 잡을 수 있어 대부분의 웹서비스에서 실전 적용이 가능합니다.
이 때문에 최근 많은 Next.js 프로젝트에서 ISR이 매우 활발히 활용되고 있습니다.
'📍 프로그래밍 언어 > Next.js' 카테고리의 다른 글
[ Next.js ] Server Component와 Client Component 완전 이해하기 (2) | 2025.06.15 |
---|---|
[ Next.js ] App Router - 구조부터 레이아웃까지 (0) | 2025.06.14 |
[ Next.js ] getStaticPaths의 fallback 옵션 설정하기(false/blocking/true) (2) | 2025.06.10 |
[ Next.js ] SSG (Static Site Generation) (0) | 2025.05.22 |
[ Next.js ] getServerSideProps로 배우는 SSR (Server Side Rendering) (0) | 2025.05.22 |