Next.js의 캐싱
Next.js는 렌더링 작업과 데이터 요청을 캐싱하여 애플리케이션의 성능을 향상시키고 비용을 절감합니다. 이 페이지에서는 Next.js의 캐싱 메커니즘, 이를 구성하는 데 사용할 수 있는 API, 그리고 이들이 서로 어떻게 상호작용하는지에 대해 자세히 살펴봅니다.
알아두면 좋은 점: 이 페이지는 Next.js가 내부적으로 어떻게 작동하는지 이해하는 데 도움이 되지만, Next.js를 생산적으로 사용하는 데 필수적인 지식은 아닙니다. Next.js의 대부분의 캐싱 방식은 API 사용에 따라 결정되며, 최상의 성능을 위해 제로 또는 최소한의 구성으로 기본값이 설정되어 있습니다. 대신 예제로 바로 넘어가고 싶다면, 여기서 시작하세요.
개요
다음은 다양한 캐싱 메커니즘과 그 목적에 대한 개요입니다:
메커니즘 | 무엇을 | 어디서 | 목적 | 지속 기간 |
---|---|---|---|---|
요청 메모이제이션 | 함수의 반환 값 | 서버 | React 컴포넌트 트리에서 데이터 재사용 | 요청 수명 주기당 |
데이터 캐시 | 데이터 | 서버 | 사용자 요청과 배포 간 데이터 저장 | 지속적 (재검증 가능) |
전체 경로 캐시 | HTML 및 RSC 페이로드 | 서버 | 렌더링 비용 감소 및 성능 향상 | 지속적 (재검증 가능) |
라우터 캐시 | RSC 페이로드 | 클라이언트 | 탐색 시 서버 요청 감소 | 사용자 세션 또는 시간 기반 |
기본적으로 Next.js는 성능을 향상시키고 비용을 줄이기 위해 가능한 한 많이 캐시합니다. 이는 기본 설정에서 제외하지 않는 한 경로가 정적으로 렌더링되고 데이터 요청이 캐시된다는 것을 의미합니다. 아래 다이어그램은 기본 캐싱 동작을 보여줍니다: 경로가 빌드 시 정적으로 렌더링될 때와 정적 경로를 처음 방문할 때의 동작입니다.

캐싱 동작은 경로가 정적으로 렌더링되는지 동적으로 렌더링되는지, 데이터가 캐시되었는지 캐시되지 않았는지, 그리고 요청이 초기 방문의 일부인지 후속 탐색의 일부인지에 따라 달라집니다. 사용 사례에 따라 개별 경로와 데이터 요청에 대한 캐싱 동작을 구성할 수 있습니다.
요청 메모이제이션
Next.js는 fetch
API를 확장하여 동일한 URL과 옵션을 가진 요청을 자동으로 메모이제이션합니다. 이는 React 컴포넌트 트리의 여러 위치에서 동일한 데이터에 대한 fetch 함수를 호출할 수 있지만 한 번만 실행한다는 것을 의미합니다.

예를 들어, 경로 전체에서 동일한 데이터를 사용해야 하는 경우(예: 레이아웃, 페이지 및 여러 컴포넌트에서), 트리 상단에서 데이터를 가져와 컴포넌트 간에 props를 전달할 필요가 없습니다. 대신, 동일한 데이터에 대해 네트워크를 통해 여러 요청을 하는 성능 영향을 걱정하지 않고 필요한 컴포넌트에서 데이터를 가져올 수 있습니다.
async function getItem() {
// `fetch` 함수는 자동으로 메모이제이션되고 결과가
// 캐시됩니다
const res = await fetch("https://.../item/1");
return res.json();
}
// 이 함수는 두 번 호출되지만 처음에만 실행됩니다
const item = await getItem(); // 캐시 MISS
// 두 번째 호출은 경로의 어디에서나 있을 수 있습니다
const item = await getItem(); // 캐시 HIT
async function getItem() {
// `fetch` 함수는 자동으로 메모이제이션되고 결과가
// 캐시됩니다
const res = await fetch("https://.../item/1");
return res.json();
}
// 이 함수는 두 번 호출되지만 처음에만 실행됩니다
const item = await getItem(); // 캐시 MISS
// 두 번째 호출은 경로의 어디에서나 있을 수 있습니다
const item = await getItem(); // 캐시 HIT
요청 메모이제이션의 작동 방식

- 경로를 렌더링하는 동안, 특정 요청이 처음 호출될 때 그 결과는 메모리에 없으므로 캐시
MISS
가 됩니다. - 따라서 함수가 실행되고, 외부 소스에서 데이터가 가져와지며, 결과는 메모리에 저장됩니다.
- 동일한 렌더링 패스에서 해당 요청의 후속 함수 호출은 캐시
HIT
가 되며, 함수를 실행하지 않고 메모리에서 데이터가 반환됩니다. - 경로가 렌더링되고 렌더링 패스가 완료되면 메모리가 "리셋"되고 모든 요청 메모이제이션 항목이 지워집니다.
알아두면 좋은 점:
- 요청 메모이제이션은 Next.js 기능이 아닌 React 기능입니다. 여기에 포함된 이유는 다른 캐싱 메커니즘과 어떻게 상호작용하는지 보여주기 위해서입니다.
- 메모이제이션은
fetch
요청의GET
메서드에만 적용됩니다.- 메모이제이션은 React 컴포넌트 트리에만 적용됩니다. 이는 다음을 의미합니다:
generateMetadata
,generateStaticParams
, 레이아웃, 페이지 및 기타 서버 컴포넌트의fetch
요청에 적용됩니다.- React 컴포넌트 트리의 일부가 아니므로 라우트 핸들러의
fetch
요청에는 적용되지 않습니다.fetch
가 적합하지 않은 경우(예: 일부 데이터베이스 클라이언트, CMS 클라이언트 또는 GraphQL 클라이언트), Reactcache
함수를 사용하여 함수를 메모이제이션할 수 있습니다.
지속 기간
캐시는 React 컴포넌트 트리 렌더링이 완료될 때까지 서버 요청의 수명 동안 지속됩니다.
재검증
메모이제이션은 서버 요청 간에 공유되지 않고 렌더링 중에만 적용되므로 재검증할 필요가 없습니다.
기본 설정에서 제외하기
메모이제이션은 fetch
요청의 GET
메서드에만 적용되며, POST
및 DELETE
와 같은 다른 메서드는 메모이제이션되지 않습니다. 이 기본 동작은 React의 최적화이며 기본 설정에서 제외하지 않는 것을 권장합니다.
개별 요청을 관리하려면 AbortController
의 signal
속성을 사용할 수 있습니다. 그러나 이는 요청을 메모이제이션에서 제외하는 것이 아니라 진행 중인 요청을 중단합니다.
const { signal } = new AbortController();
fetch(url, { signal });
데이터 캐시
Next.js에는 들어오는 서버 요청과 배포 간에 데이터 가져오기 결과를 지속하는 내장 데이터 캐시가 있습니다. 이는 Next.js가 서버의 각 요청이 자체 영구 캐싱 의미를 설정할 수 있도록 네이티브 fetch
API를 확장하기 때문에 가능합니다.
알아두면 좋은 점: 브라우저에서
fetch
의cache
옵션은 요청이 브라우저의 HTTP 캐시와 어떻게 상호작용할지를 나타내는 반면, Next.js에서cache
옵션은 서버 측 요청이 서버의 데이터 캐시와 어떻게 상호작용할지를 나타냅니다.
기본적으로 fetch
를 사용하는 데이터 요청은 캐시되지 않습니다. fetch
의 cache
및 next.revalidate
옵션을 사용하여 캐싱 동작을 구성할 수 있습니다.
데이터 캐시의 작동 방식

- 렌더링 중에
'force-cache'
옵션이 있는fetch
요청이 처음 호출될 때, Next.js는 데이터 캐시에서 캐시된 응답을 확인합니다. - 캐시된 응답이 발견되면 즉시 반환되고 메모이제이션됩니다.
- 캐시된 응답이 발견되지 않으면 데이터 소스에 요청이 이루어지고, 결과는 데이터 캐시에 저장되며 메모이제이션됩니다.
- 캐시되지 않은 데이터(예:
cache
옵션이 정의되지 않았거나{ cache: 'no-store' }
를 사용하는 경우)의 경우, 결과는 항상 데이터 소스에서 가져와지고 메모이제이션됩니다. - 데이터가 캐시되었는지 여부에 관계없이 요청은 항상 메모이제이션되어 React 렌더링 과정 동안 동일한 데이터에 대한 중복 요청을 피합니다.
데이터 캐시와 요청 메모이제이션의 차이점
두 캐싱 메커니즘 모두 캐시된 데이터를 재사용하여 성능을 향상시키지만, 데이터 캐시는 들어오는 요청과 배포 간에 지속되는 반면 메모이제이션은 요청의 수명 동안만 지속됩니다.
메모이제이션을 통해 우리는 동일한 렌더링 패스에서 렌더링 서버에서 데이터 캐시 서버(예: CDN 또는 엣지 네트워크) 또는 데이터 소스(예: 데이터베이스 또는 CMS)로 네트워크 경계를 넘어야 하는 중복 요청의 수를 줄입니다. 데이터 캐시를 통해 우리는 원본 데이터 소스에 대한 요청 수를 줄입니다.
지속 기간
데이터 캐시는 재검증하거나 기본 설정에서 제외하지 않는 한 들어오는 요청과 배포 간에 지속됩니다.
재검증
캐시된 데이터는 두 가지 방법으로 재검증할 수 있습니다:
- 시간 기반 재검증: 일정 시간이 지나고 새로운 요청이 이루어진 후 데이터를 재검증합니다. 이는 자주 변경되지 않고 최신 상태가 그다지 중요하지 않은 데이터에 유용합니다.
- 온디맨드 재검증: 이벤트(예: 폼 제출)를 기반으로 데이터를 재검증합니다. 온디맨드 재검증은 태그 기반 또는 경로 기반 접근 방식을 사용하여 한 번에 데이터 그룹을 재검증할 수 있습니다. 이는 최신 데이터를 가능한 한 빨리 표시하고 싶을 때 유용합니다(예: 헤드리스 CMS의 콘텐츠가 업데이트되었을 때).
시간 기반 재검증
시간 간격으로 데이터를 재검증하려면 fetch
의 next.revalidate
옵션을 사용하여 리소스의 캐시 수명(초 단위)을 설정할 수 있습니다.
// 최대 1시간마다 재검증
fetch("https://...", { next: { revalidate: 3600 } });
또는 라우트 세그먼트 구성 옵션을 사용하여 세그먼트의 모든 fetch
요청을 구성하거나 fetch
를 사용할 수 없는 경우에 사용할 수 있습니다.
시간 기반 재검증의 작동 방식

revalidate
가 있는 fetch 요청이 처음 호출될 때, 데이터는 외부 데이터 소스에서 가져와져 데이터 캐시에 저장됩니다.- 지정된 시간 프레임(예: 60초) 내에 호출되는 모든 요청은 캐시된 데이터를 반환합니다.
- 시간 프레임이 지난 후, 다음 요청은 여전히 캐시된(이제는 오래된) 데이터를 반환합니다.
- Next.js는 백그라운드에서 데이터 재검증을 트리거합니다.
- 데이터가 성공적으로 가져와지면 Next.js는 데이터 캐시를 새로운 데이터로 업데이트합니다.
- 백그라운드 재검증이 실패하면 이전 데이터는 변경되지 않은 채로 유지됩니다.
이는 stale-while-revalidate 동작과 유사합니다.
온디맨드 재검증
데이터는 경로(revalidatePath
)별로 또는 캐시 태그(revalidateTag
)별로 온디맨드로 재검증할 수 있습니다.
온디맨드 재검증의 작동 방식

fetch
요청이 처음 호출될 때, 데이터는 외부 데이터 소스에서 가져와져 데이터 캐시에 저장됩니다.- 온디맨드 재검증이 트리거되면 적절한 캐시 항목이 캐시에서 제거됩니다.
- 이는 시간 기반 재검증과 다릅니다. 시간 기반 재검증은 새로운 데이터를 가져올 때까지 오래된 데이터를 캐시에 유지합니다.
- 다음 요청 시, 다시 캐시
MISS
가 되어 데이터는 외부 데이터 소스에서 가져와져 데이터 캐시에 저장됩니다.
기본 설정에서 제외하기
fetch
요청은 기본적으로 캐시되지 않으므로 캐싱을 기본 설정에서 제외할 필요가 없습니다. 이는 fetch
가 호출될 때마다 데이터 소스에서 데이터를 가져온다는 의미입니다.
참고: 데이터 캐시는 현재 레이아웃, 페이지 및 라우트 핸들러에서만 사용할 수 있으며 미들웨어에서는 사용할 수 없습니다. 미들웨어 내에서 수행되는 모든 가져오기는 기본적으로 캐시되지 않습니다.
Vercel 데이터 캐시
Next.js 애플리케이션이 Vercel에 배포된 경우, Vercel 데이터 캐시 문서를 읽어 Vercel 특정 기능을 더 잘 이해하는 것이 좋습니다.
전체 경로 캐시
관련 용어:
자동 정적 최적화, 정적 사이트 생성, 또는 정적 렌더링이라는 용어가 애플리케이션의 경로를 빌드 시에 렌더링하고 캐싱하는 과정을 지칭하는 데 서로 바꿔 사용되는 것을 볼 수 있습니다.
Next.js는 자동으로 빌드 시에 경로를 렌더링하고 캐시합니다. 이는 모든 요청에 대해 서버에서 렌더링하는 대신 캐시된 경로를 제공할 수 있게 하는 최적화로, 더 빠른 페이지 로드를 가능하게 합니다.
전체 경로 캐시가 어떻게 작동하는지 이해하려면 React가 렌더링을 어떻게 처리하는지, 그리고 Next.js가 결과를 어떻게 캐시하는지 살펴보는 것이 도움이 됩니다:
1. 서버에서의 React 렌더링
서버에서 Next.js는 React의 API를 사용하여 렌더링을 조율합니다. 렌더링 작업은 개별 경로 세그먼트와 Suspense 경계에 의해 청크로 나뉩니다.
각 청크는 두 단계로 렌더링됩니다:
- React는 서버 컴포넌트를 React 서버 컴포넌트 페이로드라고 하는 스트리밍에 최적화된 특별한 데이터 형식으로 렌더링합니다.
- Next.js는 React 서버 컴포넌트 페이로드와 클라이언트 컴포넌트 JavaScript 지침을 사용하여 서버에서 HTML을 렌더링합니다.
이는 모든 것이 렌더링될 때까지 기다릴 필요 없이 작업이 완료되는 대로 응답을 스트리밍할 수 있다는 것을 의미합니다.
React 서버 컴포넌트 페이로드란 무엇인가요?
React 서버 컴포넌트 페이로드는 렌더링된 React 서버 컴포넌트 트리의 컴팩트한 바이너리 표현입니다. React가 클라이언트에서 브라우저의 DOM을 업데이트하는 데 사용됩니다. React 서버 컴포넌트 페이로드에는 다음이 포함됩니다:
- 서버 컴포넌트의 렌더링 결과
- 클라이언트 컴포넌트가 렌더링되어야 할 위치에 대한 플레이스홀더와 그들의 JavaScript 파일에 대한 참조
- 서버 컴포넌트에서 클라이언트 컴포넌트로 전달된 모든 props
자세한 내용은 서버 컴포넌트 문서를 참조하세요.
2. 서버에서의 Next.js 캐싱 (전체 경로 캐시)

Next.js의 기본 동작은 서버에서 경로의 렌더링 결과(React 서버 컴포넌트 페이로드 및 HTML)를 캐시하는 것입니다. 이는 빌드 시 또는 재검증 중 정적으로 렌더링된 경로에 적용됩니다.
3. 클라이언트에서의 React 하이드레이션 및 조정
요청 시, 클라이언트에서:
- HTML은 클라이언트 및 서버 컴포넌트의 빠른 비대화형 초기 미리보기를 즉시 표시하는 데 사용됩니다.
- React 서버 컴포넌트 페이로드는 클라이언트 및 렌더링된 서버 컴포넌트 트리를 조정하고 DOM을 업데이트하는 데 사용됩니다.
- JavaScript 지침은 클라이언트 컴포넌트를 하이드레이트하고 애플리케이션을 대화형으로 만드는 데 사용됩니다.
4. 클라이언트에서의 Next.js 캐싱 (라우터 캐시)
React 서버 컴포넌트 페이로드는 클라이언트 측 라우터 캐시에 저장됩니다 - 개별 경로 세그먼트로 분할된 별도의 인메모리 캐시입니다. 이 라우터 캐시는 이전에 방문한 경로를 저장하고 미래의 경로를 미리 가져옴으로써 탐색 경험을 개선하는 데 사용됩니다.
5. 후속 탐색
후속 탐색이나 미리 가져오기 중에 Next.js는 React 서버 컴포넌트 페이로드가 라우터 캐시에 저장되어 있는지 확인합니다. 그렇다면 서버에 새 요청을 보내지 않습니다.
만약 경로 세그먼트가 캐시에 없다면, Next.js는 서버에서 React 서버 컴포넌트 페이로드를 가져와 클라이언트의 라우터 캐시를 채웁니다.
정적 및 동적 렌더링
경로가 빌드 시에 캐시되는지 여부는 정적으로 렌더링되는지 동적으로 렌더링되는지에 따라 달라집니다. 정적 경로는 기본적으로 캐시되는 반면, 동적 경로는 요청 시 렌더링되며 캐시되지 않습니다.
이 다이어그램은 캐시된 데이터와 캐시되지 않은 데이터를 가진 정적 및 동적으로 렌더링된 경로 간의 차이를 보여줍니다:

정적 및 동적 렌더링에 대해 자세히 알아보세요.
지속 기간
기본적으로 전체 경로 캐시는 지속적입니다. 이는 렌더링 출력이 사용자 요청 간에 캐시된다는 것을 의미합니다.
무효화
전체 경로 캐시를 무효화할 수 있는 두 가지 방법이 있습니다:
- 데이터 재검증: 데이터 캐시를 재검증하면 서버에서 컴포넌트를 다시 렌더링하고 새로운 렌더링 출력을 캐싱함으로써 라우터 캐시를 차례로 무효화합니다.
- 재배포: 데이터 캐시와 달리 배포 간에 지속되는 전체 경로 캐시는 새로운 배포 시 지워집니다.
기본 설정에서 제외하기
다음과 같은 방법으로 전체 경로 캐시를 기본 설정에서 제외하거나, 다시 말해 들어오는 모든 요청에 대해 컴포넌트를 동적으로 렌더링할 수 있습니다:
- 동적 함수 사용: 이는 전체 경로 캐시에서 경로를 기본 설정에서 제외하고 요청 시 동적으로 렌더링합니다. 데이터 캐시는 여전히 사용될 수 있습니다.
dynamic = 'force-dynamic'
또는revalidate = 0
경로 세그먼트 구성 옵션 사용: 이는 전체 경로 캐시와 데이터 캐시를 건너뜁니다. 즉, 컴포넌트가 렌더링되고 서버로 들어오는 모든 요청에 대해 데이터가 가져와집니다. 라우터 캐시는 클라이언트 측 캐시이므로 여전히 적용됩니다.- 데이터 캐시 해제: 경로에 캐시되지 않은
fetch
요청이 있으면 이는 전체 경로 캐시에서 경로를 기본 설정에서 제외합니다. 특정fetch
요청에 대한 데이터는 들어오는 모든 요청에 대해 가져와집니다. 캐싱을 기본 설정에서 제외하지 않은 다른fetch
요청은 여전히 데이터 캐시에 캐시됩니다. 이를 통해 캐시된 데이터와 캐시되지 않은 데이터의 하이브리드가 가능합니다.
클라이언트 측 라우터 캐시
Next.js에는 레이아웃, 로딩 상태 및 페이지로 분할된 경로 세그먼트의 RSC 페이로드를 저장하는 인메모리 클라이언트 측 라우터 캐시가 있습니다.
사용자가 경로 간을 탐색할 때 Next.js는 방문한 경로 세그먼트를 캐시하고 사용자가 탐색할 가능성이 높은 경로를 미리 가져옵니다. 이는 즉각적인 뒤로/앞으로 탐색, 탐색 간 전체 페이지 리로드 없음, React 상태 및 브라우저 상태 보존을 가능하게 합니다.
라우터 캐시를 사용하면:
- 레이아웃은 탐색 시 캐시되고 재사용됩니다(부분 렌더링).
- 로딩 상태는 즉각적인 로딩 상태를 위해 탐색 시 캐시되고 재사용됩니다.
- 페이지는 기본적으로 캐시되지 않지만 브라우저의 뒤로 및 앞으로 탐색 중에 재사용됩니다. 실험적인
staleTimes
구성 옵션을 사용하여 페이지 세그먼트에 대한 캐싱을 활성화할 수 있습니다.
알아두면 좋은 점: 이 캐시는 특별히 Next.js와 서버 컴포넌트에 적용되며, 브라우저의 bfcache와는 다르지만 유사한 결과를 가집니다.
지속 기간
캐시는 브라우저의 임시 메모리에 저장됩니다. 라우터 캐시가 지속되는 기간을 결정하는 두 가지 요소가 있습니다:
- 세션: 캐시는 탐색 간에 지속됩니다. 그러나 페이지 새로고침 시 지워집니다.
- 자동 무효화 기간: 레이아웃 및 로딩 상태의 캐시는 특정 시간 후에 자동으로 무효화됩니다. 기간은 리소스가 어떻게 미리 가져와졌는지와 리소스가 정적으로 생성되었는지에 따라 달라집니다:
- 기본 미리 가져오기 (
prefetch={null}
또는 지정되지 않음): 동적 페이지의 경우 캐시되지 않음, 정적 페이지의 경우 5분 - 전체 미리 가져오기 (
prefetch={true}
또는router.prefetch
): 정적 및 동적 페이지 모두 5분
- 기본 미리 가져오기 (
페이지 새로고침은 모든 캐시된 세그먼트를 지우는 반면, 자동 무효화 기간은 미리 가져온 시점부터 개별 세그먼트에만 영향을 미칩니다.
알아두면 좋은 점: 실험적인
staleTimes
구성 옵션을 사용하여 위에서 언급한 자동 무효화 시간을 조정할 수 있습니다.
무효화
라우터 캐시를 무효화할 수 있는 두 가지 방법이 있습니다:
- 서버 액션에서:
- (
revalidatePath
)로 경로별 또는 (revalidateTag
)로 캐시 태그별로 데이터를 온디맨드로 재검증 cookies.set
또는cookies.delete
사용은 쿠키를 사용하는 경로가 오래되는 것을 방지하기 위해 라우터 캐시를 무효화합니다(예: 인증).
- (
router.refresh
를 호출하면 라우터 캐시를 무효화하고 현재 경로에 대해 서버에 새로운 요청을 합니다.
기본 설정에서 제외하기
Next.js 15부터 페이지 세그먼트는 기본적으로 설정에서 제외됩니다.
알아두면 좋은 점:
<Link>
컴포넌트의prefetch
prop을false
로 설정하여 미리 가져오기를 기본설정에서 제외 할 수도 있습니다.
캐시 상호작용
다양한 캐싱 메커니즘을 구성할 때 그들이 서로 어떻게 상호작용하는지 이해하는 것이 중요합니다:
데이터 캐시와 전체 경로 캐시
- 데이터 캐시를 재검증하거나 설정에서 제외하면 전체 경로 캐시가 무효화됩니다. 렌더링 출력이 데이터에 의존하기 때문입니다.
- 전체 경로 캐시를 무효화하거나 설정에서 제외해도 데이터 캐시에는 영향을 미치지 않습니다. 캐시된 데이터와 캐시되지 않은 데이터를 모두 가진 경로를 동적으로 렌더링할 수 있습니다. 이는 페이지의 대부분이 캐시된 데이터를 사용하지만 요청 시 가져와야 하는 데이터에 의존하는 몇 개의 컴포넌트가 있을 때 유용합니다. 모든 데이터를 다시 가져오는 성능 영향을 걱정하지 않고 동적으로 렌더링할 수 있습니다.
데이터 캐시와 클라이언트 측 라우터 캐시
- 데이터 캐시와 라우터 캐시를 즉시 무효화하려면 서버 액션에서
revalidatePath
또는revalidateTag
를 사용할 수 있습니다. - 라우트 핸들러에서 데이터 캐시를 재검증하는 것은 라우트 핸들러가 특정 경로에 묶여있지 않기 때문에 라우터 캐시를 즉시 무효화하지 않습니다. 이는 하드 새로고침이나 자동 무효화 기간이 경과할 때까지 라우터 캐시가 이전 페이로드를 계속 제공한다는 것을 의미합니다.
API
다음 표는 다양한 Next.js API가 캐싱에 미치는 영향을 개괄적으로 보여줍니다:
API | 라우터 캐시 | 전체 경로 캐시 | 데이터 캐시 | React 캐시 |
---|---|---|---|---|
<Link prefetch> | 캐시 | |||
router.prefetch | 캐시 | |||
router.refresh | 재검증 | |||
fetch | 캐시 | 캐시 | ||
fetch options.cache | 캐시 또는 설정에서 제외 | |||
fetch options.next.revalidate | 재검증 | 재검증 | ||
fetch options.next.tags | 캐시 | 캐시 | ||
revalidateTag | 재검증 (서버 액션) | 재검증 | 재검증 | |
revalidatePath | 재검증 (서버 액션) | 재검증 | 재검증 | |
const revalidate | 재검증 또는 설정에서 제외 | 재검증 또는 설정에서 제외 | ||
const dynamic | 캐시 또는 설정에서 제외 | 캐시 또는 설정에서 제외 | ||
cookies | 재검증 (서버 액션) | 설정에서 제외 | ||
headers , searchParams | 설정에서 제외 | |||
generateStaticParams | 캐시 | |||
React.cache | 캐시 | |||
unstable_cache | 캐시 |
<Link>
기본적으로 <Link>
컴포넌트는 전체 경로 캐시에서 경로를 자동으로 미리 가져와 React 서버 컴포넌트 페이로드를 라우터 캐시에 추가합니다.
미리 가져오기를 비활성화하려면 prefetch
prop을 false
로 설정할 수 있습니다. 하지만 이는 캐시를 영구적으로 건너뛰지 않으며, 사용자가 경로를 방문할 때 경로 세그먼트는 여전히 클라이언트 측에서 캐시됩니다.
<Link>
컴포넌트에 대해 자세히 알아보세요.
router.prefetch
useRouter
훅의 prefetch
옵션을 사용하여 수동으로 경로를 미리 가져올 수 있습니다. 이는 React 서버 컴포넌트 페이로드를 라우터 캐시에 추가합니다.
useRouter
훅 API 참조를 참조하세요.
router.refresh
useRouter
훅의 refresh
옵션을 사용하여 수동으로 경로를 새로 고칠 수 있습니다. 이는 라우터 캐시를 완전히 지우고 현재 경로에 대해 서버에 새로운 요청을 합니다. refresh
는 데이터 캐시나 전체 경로 캐시에 영향을 미치지 않습니다.
렌더링된 결과는 React 상태와 브라우저 상태를 보존하면서 클라이언트에서 조정됩니다.
useRouter
훅 API 참조를 참조하세요.
fetch
fetch
에서 반환된 데이터는 데이터 캐시에 자동으로 캐시되지 않습니다.
// 기본적으로 캐시됩니다. `no-store`는 기본 옵션이며 생략할 수 있습니다.
fetch(`https://...`, { cache: "no-store" });
렌더링 출력이 데이터에 의존하기 때문에 cache: 'no-store'
를 사용하면 fetch
요청이 사용되는 경로에 대한 전체 경로 캐시도 건너뜁니다. 즉, 경로는 모든 요청에 대해 동적으로 렌더링되지만 동일한 경로에서 다른 캐시된 데이터 요청을 계속 가질 수 있습니다.
더 많은 옵션은 fetch
API 참조를 참조하세요.
fetch options.cache
개별 fetch
를 cache
옵션을 force-cache
로 설정하여 캐싱에 활성화 할 수 있습니다:
// 캐싱 활성화
fetch(`https://...`, { cache: "force-cache" });
더 많은 옵션은 fetch
API 참조를 참조하세요.
fetch options.next.revalidate
fetch
의 next.revalidate
옵션을 사용하여 개별 fetch
요청의 재검증 기간(초 단위)을 설정할 수 있습니다. 이는 데이터 캐시를 재검증하고, 차례로 전체 경로 캐시를 재검증합니다. 새로운 데이터가 가져와지고 서버에서 컴포넌트가 다시 렌더링됩니다.
// 최대 1시간 후에 재검증
fetch(`https://...`, { next: { revalidate: 3600 } });
더 많은 옵션은 fetch
API 참조를 참조하세요.
fetch options.next.tags
및 revalidateTag
Next.js에는 세분화된 데이터 캐싱 및 재검증을 위한 캐시 태깅 시스템이 있습니다.
fetch
또는unstable_cache
를 사용할 때 하나 이상의 태그로 캐시 항목에 태그를 지정할 수 있습니다.- 그런 다음
revalidateTag
를 호출하여 해당 태그와 관련된 캐시 항목을 제거할 수 있습니다.
예를 들어, 데이터를 가져올 때 태그를 설정할 수 있습니다:
// 태그로 데이터 캐시
fetch(`https://...`, { next: { tags: ["a", "b", "c"] } });
그런 다음 revalidateTag
를 특정 태그와 함께 호출하여 캐시 항목을 제거합니다:
// 특정 태그를 가진 항목 재검증
revalidateTag("a");
revalidateTag
를 사용할 수 있는 두 가지 위치가 있으며, 목표에 따라 선택할 수 있습니다:
- 라우트 핸들러 - 서드파티 이벤트(예: 웹훅)에 대한 응답으로 데이터를 재검증합니다. 이는 라우트 핸들러가 특정 경로에 묶여있지 않기 때문에 라우터 캐시를 즉시 무효화하지 않습니다.
- 서버 액션 - 사용자 액션(예: 폼 제출) 후 데이터를 재검증합니다. 이는 관련 경로에 대한 라우터 캐시를 무효화합니다.
revalidatePath
revalidatePath
를 사용하면 특정 경로 아래의 경로 세그먼트를 수동으로 재검증하고 단일 작업으로 다시 렌더링할 수 있습니다. revalidatePath
메서드를 호출하면 데이터 캐시를 재검증하고, 차례로 전체 경로 캐시를 무효화합니다.
revalidatePath("/");
revalidatePath
를 사용할 수 있는 두 가지 위치가 있으며, 목표에 따라 선택할 수 있습니다:
자세한 정보는 revalidatePath
API 참조를 참조하세요.
revalidatePath
vs.router.refresh
:
router.refresh
를 호출하면 라우터 캐시가 지워지고 데이터 캐시나 전체 경로 캐시를 무효화하지 않고 서버에서 경로 세그먼트를 다시 렌더링합니다.차이점은
revalidatePath
는 데이터 캐시와 전체 경로 캐시를 제거하는 반면,router.refresh()
는 클라이언트 측 API이기 때문에 데이터 캐시와 전체 경로 캐시를 변경하지 않는다는 것입니다.
동적 함수
cookies
와 headers
같은 동적 함수와 페이지의 searchParams
prop은 런타임 들어오는 요청 정보에 의존합니다. 이들을 사용하면 경로가 전체 경로 캐시에서 제외됩니다. 다시 말해, 경로가 동적으로 렌더링됩니다.
cookies
서버 액션에서 cookies.set
또는 cookies.delete
를 사용하면 쿠키를 사용하는 경로가 오래되는 것을 방지하기 위해 라우터 캐시가 무효화됩니다(예: 인증 변경 사항을 반영하기 위해).
cookies
API 참조를 참조하세요.
세그먼트 구성 옵션
라우트 세그먼트 구성 옵션은 경로 세그먼트 기본값을 재정의하거나 fetch
API를 사용할 수 없을 때(예: 데이터베이스 클라이언트 또는 서드파티 라이브러리) 사용할 수 있습니다.
다음 라우트 세그먼트 구성 옵션은 데이터 캐시와 전체 경로 캐시에서 제외합니다:
const dynamic = 'force-dynamic'
const revalidate = 0
더 많은 옵션은 라우트 세그먼트 구성 문서를 참조하세요.
generateStaticParams
동적 세그먼트(예: app/blog/[slug]/page.js
)의 경우, generateStaticParams
에 의해 제공된 경로는 빌드 시 전체 경로 캐시에 캐시됩니다. 요청 시, Next.js는 빌드 시 알려지지 않았던 경로도 처음 방문할 때 캐시합니다.
빌드 시 모든 경로를 정적으로 렌더링하려면 generateStaticParams
에 전체 경로 목록을 제공하세요:
export async function generateStaticParams() {
const posts = await fetch("https://.../posts").then((res) => res.json());
return posts.map((post) => ({
slug: post.slug,
}));
}
빌드 시 경로의 일부를 정적으로 렌더링하고 나머지는 런타임에 처음 방문할 때 렌더링하려면 부분적인 경로 목록을 반환하세요:
export async function generateStaticParams() {
const posts = await fetch("https://.../posts").then((res) => res.json());
// 빌드 시 처음 10개의 게시물 렌더링
return posts.slice(0, 10).map((post) => ({
slug: post.slug,
}));
}
모든 경로를 처음 방문할 때 정적으로 렌더링하려면 빈 배열을 반환하거나(빌드 시 렌더링되는 경로 없음) export const dynamic = 'force-static'
을 사용하세요:
export async function generateStaticParams() {
return [];
}
알아두면 좋은 점: 빈 배열이라도
generateStaticParams
에서 배열을 반환해야 합니다. 그렇지 않으면 경로가 동적으로 렌더링됩니다.
export const dynamic = "force-static";
요청 시 캐싱을 비활성화하려면 경로 세그먼트에 export const dynamicParams = false
옵션을 추가하세요. 이 구성 옵션을 사용하면 generateStaticParams
에서 제공한 경로만 제공되며, 다른 경로는 404가 되거나 일치합니다(catch-all 경로의 경우).
React cache
함수
React cache
함수를 사용하면 함수의 반환 값을 메모이제이션할 수 있어, 동일한 함수를 여러 번 호출하면서도 한 번만 실행할 수 있습니다.
fetch
요청은 자동으로 메모이제이션되므로 React cache
로 감쌀 필요가 없습니다. 하지만 fetch
API가 적합하지 않은 사용 사례에 대해 데이터 요청을 수동으로 메모이제이션하기 위해 cache
를 사용할 수 있습니다. 예를 들어, 일부 데이터베이스 클라이언트, CMS 클라이언트 또는 GraphQL 클라이언트에 사용할 수 있습니다.
import { cache } from "react";
import db from "@/lib/db";
export const getItem = cache(async (id: string) => {
const item = await db.item.findUnique({ id });
return item;
});
import { cache } from "react";
import db from "@/lib/db";
export const getItem = cache(async (id) => {
const item = await db.item.findUnique({ id });
return item;
});