(준)공식 문서/Next.js

[ Next.js 공식 문서 ] Caching

Je-chan 2024. 4. 17. 01:14

 

 

  Next.js 는 렌더링 작업과 데이터 요청을 캐싱하여 애플리케이션의 성능을 향상시키고 비용을 절감한다. 이 페이지에서는 Next.js 의 캐싱 메커니즘, 이를 구성하는데 사용할 API, 그리고 이것들이 어떻게 상호작용하는지에 대해서 설명한다.

 

  이 페이지는 Next.js 내부 작동 방식을 이해하는데 도움을 주되, Next.js 를 효과적으로 사용하기 위한 필수 지식은 아니다. Next.js 의 캐싱 휴리스틱은 대부분 API 사용에 의해 결정되며, 최소한의 구성으로도 최적의 성능을 제공하도록 기본 값이 설정돼 있다.

 


1. 개요

메커니즘 무엇을 어디서 목적 지속 시간
요청 Memoization 함수들의 반환 값 서버 React 컴포넌트 트리에서 데이터를 재사용 요청 수명 주기 당
데이터 캐시 데이터 서버 사용자 요청 및 배포간 데이터 저장 지속적 (업데이트 가능)
전체 라우트 캐시 HTML, RSC Payload 서버 렌더링 비용 감소 및 성능 향상 지속적 (업데이트 가능)
경로 캐시 RSC Payload 클라이언트 탐색 시 서버 요청 감소 사용자 session 또는 시간 기반

 

  기본적으로 Next.js 는 가능한 많은 것을 캐시하여 성능을 향상시키고 비용을 절감한다. 이는 경로들이 정적으로 렌더링되고 따로 설정해주지 않으면 데이터 요청이 캐시되는 것을 의미한다. 아래의 다이어그램은 빌드 타임에 경로가 정적으로 렌더링되고 처음 방문할 때 정적 경로의 기본 캐싱 동작을 보여준다. 

 

 

  다이어그램은 빌드 타임과 라우트가 처음 방문했을 때 Next.js 의 네 가지 메커니즘에 대한 기본 캐싱 동작을 보여주며, HIT, MISS, SET 으로 표현한다.

 

* 개인 적인 정리

HIT : 요청이 들어왔을 때 요청된 데이터가 캐시에 이미 존재하고 유효한 경우  
       : 데이터를 캐시에서 직접 검색해 성공적으로 반환할 수 있다는 것을 의미한다.
       : 추가적인 데이터 가져오기 또는 렌더링 없이 빠르게 응답을 제공한다

MISS : 요청이 발생했을 때 ㅍ필요한 데이터나 렌더링 결과가 캐시에 존재하지 않는 경우
          : 이런 경우, Next.js 는 데이터를 새로 가져오거나 페이지를 새로 렌더링한다.

SET  : MISS 후에 데이터를 가져오거나 페이지를 렌더링한 결과를 캐시에 저장
         : 다음 요청이 발생했을 때 HIT 을 통해 더 빠른 응답을 제공한다.

STALE : 경로와 관련해서, 해당 경로가 캐싱은 돼 있으나 유효한 시간이 지나서 최신 정보로 업데이트 해야하는 경우

 

  캐싱 동작은 경로가 정적으로 렌더링됐는지, 동적으로 렌더링됐는지, 데이터가 캐시됐는지, 캐시되지 않았는지, 요청이 초기 방문인지, 후속 탐색인지에 따라 달라진다. 사용 사례에 따라서 개별 라우팅 및 데이터 Fetching 에 대한 캐싱 동작들을 구성할 수 있다.


2. 요청 Memoization 

  React 는 동일한 URL 과 옵션을 가진 요청에 대해 자동으로 Memoization 하는 기능을 fetch API 에서 확장했다. 즉, React 컴포넌트 트리의 여러 곳에서 동일한 데이터에 대한 fetch 함수를 호출할 수는 있지만 실제로 한 번만 실행된다는 것을 의미한다.

 

 

  예를 들어, 경로 전반에 동일한 데이터를 사용하는 경우, 트리 상단에서 데이터를 가져와 컴포넌트 간에 props 를 전달할 필요가 없다. 대신, 필요한 컴포넌트에서 데이터를 가져와 동일한 데이터에 대해 네트워크를 여러 번 요청해도 되며, 이때 성능을 걱정할 필요가 없다.  

 

async function getItem() {
  // The `fetch` function is automatically memoized and the result
  // is cached
  const res = await fetch('https://.../item/1')
  return res.json()
}
 
// This function is called twice, but only executed the first time
const item = await getItem() // cache MISS
 
// The second call could be anywhere in your route
const item = await getItem() // cache HIT

 

 

 

  경로를 렌더링하는 동안, 특정 요청이 처음 호출 도될 때, 그 결과는 메모리에 없고 캐시 MISS 가 된다. 따라서 함수는 실행되고 외부 소스에서 데이터를 가져와 결과를 메모리에 저장한다. 같은 경로에서 이후의 요청 함수 호출은 캐시 HIT 이 되며, 함수를 실행하지 않고, 메모리에서 데이터가 반환된다. 렌더링이 완료되고 렌더링 패스가 끝나면 메모리는 리셋되고 요청 메모이제이션 항목이 사라진다.

 

  요청 Memoization 은 React 의 기능이지 Next.js 의 기능이 아니다.

  Memoization 은 오직 GET 요청 한정이다.
  Memization 은 React 컴포넌트에만 적용이 된다. 즉, 메타데이터 생성, getStaticParams(), Layouts, Pages, 다른 서버 컴포넌트들에는 해당하지 않는다.

  Route Handler 의 fetch 요청은  React 컴포넌트 트리의 일부가 아니므로 적용되지 않는다.

  fetch 가 적합하지 않은 경우(e.g. DB, CMS, GraphQL 클라이언트 등) 함수를 메모이제이션 하기 위해 React **Cache** 기능을 사용할 수 있다.

 

2-1) 지속 시간

  캐시는 서버 요청의 수명동안 지속된다. React 컴포넌트 트리의 렌더링이 완료될 때까지 유지된다.

 

2-2) 갱신

  Memoization 은 서버 요청 간에 공유되지 않는다. 렌더링 중에만 적용되기에 갱신할 필요가 없다.

 

2-3) 설정 해제

  Memoization 은 fetch 요청의 GET 메소드 한정이며, POST, DELETE 같은 다른 메소드는 Memoization 되지 않는다. 이 기본 동작은 React 의 최적화이며, 이 기능에서 설정을 해제하는 것은 좋은 방안이 아니다.

 

  개별 요청을 관리하기 위해서 **AbortController** 의 **signal** 속성을 사용할 수 있다. 이는 요청을 Memoization 에서 해제하는 것 뿐만 아니라 진행 중인 요청도 중단시킨다.

 

// app/example.js

const { signal } = new AbortController();
fetch(url, { signal });

3. 데이터 캐시 

  Next.js 에는 서버 요청과 배포를 거쳐 데이터 fetch 결과를 유지하는 내장 데이터 캐시가 있다. Next.js 가 기존 fetch API 를 확장해 확장해 각 서버 요청이 자체적으로 캐싱을 지속하도록 만들었다.

 

  브라우저에서 **fetch** 의 **cache** 옵션은 요청이 브라우저의 HTTP 캐시와 어떻게 상호작용할 지를 나타낸다. Next.js 에서는 서버 사이드 요청이 서버의 데이터 캐시와 어떻게 상호작용할지를 나타낸다.

 

  기본적으로, **fetch** 를 사용하는 데이터 요청은 캐시된다. **fetch** 의 **chache** 혹은 **next.revalidate** 옵션을 사용해서 캐싱 방식을 설정할 수 있다. 

 

 

  1. 렌더링 중 fetch 요청이 처음 호출될 때, Next.js 는 "Data Cache" 에서 캐시된 응답을 확인한다.
  2. 캐시된 응답이 발견되면 즉시 반환하고 요청을 Memoization 한다
  3. 캐시된 응답이 발견되지 않으면 요청이 "Data Source" 로 이동하고, 결과가 "Data Cache" 에 저장되며 요청은 Memoization 된다.
  4. 캐시되지 않은 데이터(e.g. { cache: 'no-store' })는, 결과가 항상 "Data Source" 에서 fetch 되고 요청만 Memoization ehlsek.
  5. 데이터가 캐시됐든, 캐시되지 않았든 요청은 항상 Memoization 되고 React 렌더링 동안에 동일한 데이터에 대한 중복 요청을 방지한다.

 

  데이터 캐시와 요청 Memoization 은 캐시된 데이터를 재사용해서 성능을 향상시키는 데 도움을 주지만, 데이터 캐시는 서버 요청과 배포에 걸쳐 지속되는 반면, Memoization은 요청의 수명 동안만 지속된다.

 

   Memoization 을 사용하면 렌더링 서버에서 데이터 캐시 서버(CDN 등) 또는 "Data Source" 로 네트워크 바운더리를 넘나드는 동일 렌더링 시간 동안의 중복 요청 수를 줄일 수 있다. 데이터 캐시를 사용하면 원본 "Data Source"로의 요청 수를 줄일 수 있다.

 

 

3-1) 지속 시간

  데이터 캐시는 갱신하거나 설정 해제를 하지 않는 한, 들어오는 요청 및 배포에 걸쳐 지속된다.

 

3-2) 갱신

  캐시된 데이터는 두 가지 방법으로 갱신할 수 있다.

 

  1. 시간 기반 갱신
    : 일정 시간이 지난 후 새 요청이 발생하면 데이터를 갱신한다
    : 데이터 변경 빈도가 낮고 데이터의 최신성이 그리 중요하지 않는 경우에 유용하다.

  2. 수요 기반 갱신
    : 이벤트(폼 제출 등)를 기반으로 데이터를 갱신한다.
    : 수요 기반 갱신은 태그 기반 혹은 경로 기반 접근을 사용해서 한 번에 데이터 그룹을 갱신할 수 있다.
    : 가능한 빨리 최신 데이터를 보여주고 싶을 때 유용하다

 

(1) 시간 기반 갱신

  

  시간 간격을 설정해서 데이터를 갱신하려면 **fetch** 의 **next.revalidate** 옵션을 사용해 리소스 캐시 수명(초단위)을 설정할 수 있다.

 

// 최대 매 시간마다 재검증
fetch('https://...', { next: { revalidate: 3600 } })

 

  fetch 를 사용할 수 없는 경우에 대안으로, 모든 fetch 요청을 구성하는 **Route Segment Config** 옵션을 사용할 수 있다.

 

 

  1. **revalidate** 가 설정된 **fetch** 요청이 처음 호출될 때, 데이터는 외부 "Data Source** 에서 가져와 **Data Cache** 에 저장된다.
  2. 지정된 시간 내에 호출되는 모든 요청은 캐시된 데이터를 반환한다.
  3. 그 이후에는 다음 요청이 여전히 캐시된(하지만 이제는 Stale 된) 데이터를 반환한다.
  4. Next.js 는 백그라운드에서 데이터의 갱신을 트리거한다.
  5. 데이터를 성공적으로 가져오면, Next.js 는 새로 받은 데이터로 캐시를 업데이트한다.
  6. 백그라운드 갱신이 실패하면 이전 데이터는 변경되지 않는 상태로 유지된다

  이 방식은 마치 stale-while-revalidate(SWR) 방식과 유사하다.

 

(2) 수요 기반 갱신

  데이터가 경로(revalidatePath) 혹은 캐시 태그(revalidateTag) 에 의해 수요 기반으로 갱신될 수 있다.

 

 

  1. fetch 요청이 처음 호출될 때, 데이터는 외부 "Data Source" 에서 가져와 "Data Cache" 에 저장된다.
  2. 수요 기반 갱신이 트리거되면, 적절한 캐시 항목들이 캐시에서 제거된다.
  3. 시간 기반 갱신과는 다르게 최신 데이터가 패치될 때까지 오래된 데이터를 캐시에 유지한다.
  4. 다음 요청이 발생하면 캐시 MISS 가 발생하며, 데이터는 외부 "Data Source" 에서 가져와 "Data Cache" 에 저장된다.

 

3-2) 설정 해제

  개별 데이터 fetch 의 경우, **cache** 옵션을 'no-store' 로 설정해서 캐싱을 설정 해제할 수 있다. 이는 fetch 가 호출될 때마다 데이터가 fetch 됨을 의미한다.

 

// 개별 `fetch` 요청에 대해 캐싱 옵트 아웃
fetch(`https://...`, { cache: 'no-store' })

 

  혹은, 특정 경로 Segment 에 대한 캐싱을 설정 해제하기 위해서 **Route Segment Config** 옵션을 사용할 수도 있다. 이 경우 모든 데이터 요청에 영향을 준다.

 

// 라우트 세그먼트의 모든 데이터 요청에 대해 캐싱 옵트 아웃
export const dynamic = 'force-dynamic'

 

  데이터 캐시는 현재 페이지/경로 에서만 사용이 가능하다. 미들웨어에서는 기본적으로 캐시되지 않은 상태로 fetch 된다.


4. 전체 라우트 캐시 

  자동 정적 최적화(Automatic Static Optimization), 정적 사이트 생성(Static Site Generation), 정적 렌더링(Static Rendering) 이라는 용어가 빌드 타임에 애플리케이션의 경로를 렌더링하고 캐싱하는 과정을 지칭하는데 섞여서 사용될 수 있다.

 

  Next.js 는 빌드 타임에 자동으로 경로를 렌더링하고 캐시한다. 이는 모든 요청에 대해 서버에서 렌더링하는 대신 캐시된 경로를 제공할 수 있게 해주는 최적화로, 페이지 로드 속도를 빠르게 한다. 

 

  전체 라우트 캐시 작동 방식을 이해하려면, React 렌더링을 어떻게 처리하는지와 Next.js 결과를 어떻게 캐시하는지 살피는 것이 도움이 된다.

 

4-1) 서버에서 React 렌더링

  서버에서 Next.js 는 React API 를 사용해 렌더링을 조정한다. 렌더링 작업은 개별 경로 Segment 와 Suspense Boundary 에 따라 분할된다.

 

  각 청크는 두 단계로 나뉜다.

 

  1. React 는 서버 컴포넌트를 스트리밍에 최적화된 특별한 데이터 형식 **RSC Payload** 로 렌더링한다.
  2. Next.js 는 **RSC Payload** 와 클라이언트 컴포넌트 JS 지시사항 을 사용해서 서버에서 HTML 을 렌더링한다 

  작업을 캐시하거나 응답을 보내기 전 모든 것을 렌더링할 필요가 없다. 대신, 작업이 완료됨에 따라 응답을 스트리밍할 수 있다.

 

  **RSC Payload** 란 렌더링된 React 서버 컴포넌트 트리의 간결한 이진 표현이다. 클라이언트에서 React 가 DOM 을 업데이트 할 때 사용한다. React 서버 컴포넌트 페이로드에는 다음의 내용이 포함된다. 

  •   서버 컴포넌트의 렌더링 결과
  •   클라이언트 컴포넌트가 렌더링될 위치의 placeholder 와 그와 관련된 자바스크립트 파일 참조
  • 서버 컴포넌트에서 클라이언트 컴포넌트로 전달된 모든 Props

 

4-2) 서버에서 Next.js 캐싱(전체 라우트 캐시)

  기본적으로 Next.js 는 정적으로 렌더링된 경로에 대해 서버에서 **RSC Payload** 와 HTML 을 캐시한다. 이는 빌드 시간 또는 갱신 동안에 적용된다.

 

4-3) 클라이언트에서 React hydration 과 조정

  요청시, 클라이언트에서는 다음의 과정을 거친다

 

  1. HTML 은 클라이언트와 서버컴포넌트의 빠르고 상호작용할 수 없는 미리보기 형태로 즉시 보여준다.
  2. **RSC Payload** 는 클라이언트와 렌더링된 서버 컴포넌트 트리를 조정하고 DOM 을 업데이트하는데 사용한다.
  3. JS 지시사항은 클라이언트 컴포넌트를 hydration 하고 애플리케이션이 상호작용 가능한 형태로 만든다

 

4-3) 클라이언트에서 Next.js 캐싱 (경로 캐시)

  **RSC Payload** 는 클라이언트 사이드의 **Router Cache** 라는 곳에 저장된다. 이곳은 별도의 인메모리 캐시이며 개별 경로 Segment 마다 분리돼 있다. 이 **Router Cache** 는 사전에 방문한 경로들을 저장하고 미래에 방문할 경로를 Prefetch 해서 탐색 경험을 개선한다.

 

4-4) 후속 탐색

  후속 탐색이나 Prefetch 를 하는 동안, Next.js 는 **RSC Payload** 가 **Router Cache** 에 저장돼있는지 확인한다. 저장돼 있다면 새 요청을 서버로 보내는 것을 건너뛴다.

 

  만약, 경로 Segment 에 캐시가 없다면, Next.js 는 서버로 RSC Payload 를 요청해서 가져온 다음 클라이언트의 *Router Cache** 를 채운다.

 

4-5) 정적 및 동적 렌더링

  경로가 빌드 타임에 캐시되는지 여부는 정적으로 렌더링되는지 혹은 동적으로 렌더링되는지에 따라 다르다. 정적 렌더링은 기본적으로 캐시가 된다. 동적 렌더링은 요청 시 렌더링되고 캐시되지 않는다.

 

 

 

4-6) 지속 시간

  기본적으로 전체 라우트 캐시는 지속적이다. 사용자 요청 간에 렌더링 출력이 캐시됨을 의미한다.

 

4-7) 무효화

  전체 라우트 캐시를 무효화 할 수 있는 방법에는 두 가지가 있다.

 

  1. 데이터 갱신
    : 데이터 캐시를 갱신하면 서버에서 컴포넌트를 리렌더링하고 새로운 렌더링 값을 캐싱하여 **Router Cache** 자체를 무효화한다.
  2. 재배포
    : 데이터 캐시가 배포 간에 지속되는 반면, 전체 라우트 캐시는 배포시에 사라진다.

 

4-8) 설정 해제

  전체 라우트 캐시를 설정 해제하고싶을 때, 즉 모든 요청에 대해 동적으로 컴포넌트를 렌더링하고 싶다면 다음을 사용할 수 있다.

 

  1. 동적 함수 사용
    : 경로를 전체 라우트 캐시에서 제외하고 요청 시에 동적으로 렌더링한다. 데이터 캐시는 여전히 사용 가능하다.

  2. 경로 Segment 옵션에서 **dynamic = 'force-dynamic'** 혹은 'revalidate = 0' 옵션 사용
    : 전체 라우트 캐시와 데이터 캐시를 건너 뛰고, 서버로 들어오는 모든 요청에 대해 컴포넌트를 렌더링하고 데이터를 fetch 한다. 경로 캐시는 클라이언트 사이드 캐시로 여전히 적용된다.

  3. 데이터 캐시를 설정 해제
    : 캐시되지 않은 fetch 요청이 있는 경로의 경우, 경로를 전체 라우트 캐시에서 제외한다. 특정 fetch 요청에 대한 데이터는 모든 요청들에 대해서 fetch 한다. 캐싱에서 설정 해제 하지 않은 다른 fetch 요청은 데이터 캐시에 계속 캐시된다. 이를 통해, 캐시된 데이터와 캐시되지 않은 데이터의 혼합이 가능하다.

5. 라우터 캐시 

 경로 캐시는 클라이언트 측 캐시 혹은 Prefetch 캐시로도 언급될 수 있다. Prefetch 캐시는 Prefetch 된 경로 Segment 를 가리키는 반면, 클라이언트 사이드 캐시는 방문한 Segment 와 Prefetch 된 Segment 를 모두 포함하는 전체 라우트 캐시를 의미한다. 이 캐시는 Next.js 와 서버 컴포넌트에 특별히 적용되며, 브라우저의 bfcache 와는 다르지만 유사한 결과를 제공한다.

 

  Next.js 는 사용자 세션동안 개별 경로 Segment 로 분할된 **RSC Payload** 를 저장하는 클라이언트 사이드 인-메모리 캐시를 가지고 있다. 이것을 라우터 캐시라고 부른다.

 

  

  사용자가 경로 간에 탐색할 때, Next.js 는 방문한 경로 Segment 를 캐시하고 사용자가 탐색할 가능성이 있는 경로를 Prefetch 한다 (`<Link>` 컴포넌트가 뷰포트에 있을 것을 기반으로)

 

  이는 사용자에게 개선된 탐색 경험을 제공한다.

 

  •  방문한 경로가 캐시돼 있기에 순간적인 앞뒤 탐색이 가능하고, Prefetching 및 부분 렌더링으로 인해 새로운 경로로의 빠른 탐색이 가능하다. 
  • 탐색 간, 전체 페이지 새로 고침이 없고, React 상태와 브라우저 상태가 유지된다.

  라우터 캐시는 사용자 세션 동안 브라우저에 **RSC Payload** 를 일시적으로 저장하는 반면, 전체 라우트 캐시는 서버에 **RSC Payload** 와 HTML 을 지속적으로 저장한다. 전체 라우트 캐시는 정적으로 렌더링된 라우트만 캐시하는 반면, 라우터 캐시는 동적으로 렌더링된 라우트까지도 포함한다.

 

5-1) 지속 시간

  캐시는 브라우저의 임시 메모리에 저장된다. 라우터 캐시가 지속되는 기간은 두 가지 요소에 의해 결정된다.

 

  1. 세션
    : 캐시는 탐색 간에 지속되지만, 페이지 새로 고침 시에는 지워진다.

  2. 자동 무효화 기간
    : 개별 Segment 캐시는 특정 시간 후에 자동으로 무효화된다. 지속 기간은 리소스가 prefetch 된 방법에 따라 따라 달라진다.
    : 기본 Prefetching(prefetch={null} 혹은 미지정 : 30초)
    : 전체 Prefetching(prefetch={true} 혹은 router.prefetch : 5분)

  3. 페이지 새로 고침은 모든 캐시된 Segment 를 지우지만, 자동 무효화 기간은 프리패치된 시간부터 개별 Segment 에만 영향을 준다.

 

5-2) 무효화

  라우터 캐시를 무효화할 수 있는 방법은 두 가지가 있다.

 

(1) Server Action 에서

  1. 경로별로 데이터를 갱신(수요 기반 갱신)하거나 캐시 태그로 갱신 
  2. **cookies.set** 이나 **cookies.delete** 를 사용하면 라우터 캐시가 무효화되어 쿠키를 사용하는 경로가 오래되지 않도록 한다

(2) router.refresh

  **router.refresh** 를 호출하면 라우터 캐시가 무효화되고, 서버에서 현재 라우트에 대한 새 요청을 만든다.

5-3) 설정 해제

  라우터 캐시를 설정해제할 수는 없다. 하지만 위의 방식들으로 무효화할 수는 있다. 이는 캐시를 지우고 서버에 새 요청을 만들어 최신 데이터가 표출되도록 하는 방법이다

 

  `<Link />` 컴포넌트의 **prefetch** props 를 false 로 설정해 prefetching 을 설정해제할 수 있다. 하지만 이는 여전히 30 초 동안 경로 Segment 를 일시적으로 저장해 탭바와 같은 중첩 세그먼트 간 혹은 앞뒤 탐색 간 즉각적인 탐색을 허용한다. 방문한 경로는 여전히 캐시된다.

 


6. 캐시 상호작용 

  다양한 캐싱 메커니즘을 구성할 때 이들이 서로 어떻게 상호작용하는지 이해하는 것이 중요하다.

 

5-1) 데이터 캐시 및 전체 라우트 캐시

  데이터 캐시를 재검증하거나 설정해제하면 렌더링 출력이 데이터에 의존하기에 전체 라우트 캐시가 무효화된다.

 

  전체 라우트 캐시를 무효화하거나 설정해제 하더라도 데이터 캐시에는 영향을 주지 않는다. 캐시된 데이터와 캐시되지 않은 데이터가 모두 있는 경로를 동적으로 렌더링할 수 있다. 대부분의 페이지가 캐시된 데이터를 사용한다. 하지만, 요청 시에 fetch 해야 하는 데이터에 의존하는 몇 컴포넌트가 있는 경우 유용하다. 모든 데이터를 다시 패치하는 성능 영향에 대한 걱정을 하지 않고 동적으로 렌더링할 수 있다.

 

5-2) 데이터 캐시 및 클라이언트 사이드 라우터 캐시

  **Route Handler** 에서 데이터 캐시를 갱신하더라도 라우터 캐시는 즉시 무효화되지 않는다. 이는 라우터 핸들러가 특정 경로에 연결돼 있지 않기 때문이다. 이는 Hard refresh 가 발생하거나 자동 무효화 기간이 경과할 때까지 라우터 캐시가 이전 **RSC Payload** 를 제공한다는 것을 의미한다.

 

  데이터 캐시 및 라우터 캐시를 즉시 무효화하고 싶다면 서버에서 **revalidatePath** 나 **revalidateTag** 를 사용할 수 있다.


Reference

 

https://nextjs.org/docs/app/building-your-application/caching#duration-2

 

Building Your Application: Caching | Next.js

An overview of caching mechanisms in Next.js.

nextjs.org