[Next.js] Caching

이희주·2025년 2월 27일

Next.js

목록 보기
5/7
post-thumbnail

Next.js에서는 성능을 개선하고 비용을 줄이기 위해 다양한 캐시를 지원한다. Request Memoization (요청 메모이제이션), Data Cache (데이터 캐시), Full Route Cache (전체 경로 캐시), Client Router Cache (클라이언트 라우터 캐시)를 통해 Next.js의 캐싱 메커니즘, 이를 구성하는 데 사용할 수 있는 API, 이들이 서로 상호 작용하는 방식에 대해 자세히 살펴보자.

✅ Request Memoization (요청 메모이제이션)

Next.js는 동일한 요청을 한 번만 수행하도록 자동으로 메모이제이션(기억)한다.
예를 들어, fetch동일한 URL로 여러 번 호출하면 Next.js는 한 번만 요청을 수행하고, 그 결과를 재사용한다.

async function getData() {
  const res = await fetch('https://example.com/api/data');
  return res.json();
}

// getData()를 여러 번 호출해도 Next.js는 동일한 요청을 중복 수행하지 않는다.
export default async function Page() {
  const data1 = await getData(); // 실제 요청 수행
  const data2 = await getData(); // 캐시된 결과를 사용

  return <div>{data1.someValue}</div>;
}

✔️ Request Memoization 작동방식

  1. 경로를 렌더링하는 동안 특정 요청이 처음 호출되면 결과는 메모리에 저장되지 않고 캐시에 저장된다 MISS.
  2. 따라서 해당 함수가 실행되고, 외부 소스에서 데이터를 가져오고, 그 결과가 메모리에 저장된다.
  3. 동일한 렌더 패스에서 요청에 대한 후속 함수 호출은 캐시가 되고 HIT, 함수를 실행하지 않고도 메모리에서 데이터가 반환된다.
  4. 경로가 렌더링되고 렌더링 패스가 완료되면 메모리가 '재설정'되고 모든 요청 메모 항목이 지워진다.

✔️ Request Memoization 특징

  • 하나의 페이지를 렌더링 하는 동안에 중복된 API 요청을 캐싱하기 위해 존재한다.
  • 렌더링이 종료되면 모든 캐시가 소멸된다.

App Router에서는 React Server Component의 도입으로 각각의 컴포넌트에서 데이터를 직접 요청할 수 있게 되었다. 때문에 하나의 페이지에서 여러 컴포넌트가 존재하는 경우에, 서로 다른 컴포넌트에서 동일한 데이터를 필요로 하는 경우가 발생할 수 밖에 없어졌다.

이를 위해서 Next.js 동일한 요청을 한 번만 수행하도록 자동으로 메모이제이션하고, 이는 동일한 데이터 요청을 중복으로 보내는 것을 방지하여 성능을 최적화한다.


✅ Data Cache (데이터 캐시)

✔️ Data Cache 작동방식

fetch()를 사용하여 캐시를 활성화할 수 있으며, 동일한 요청은 다시 실행되지 않고 캐시된 응답이 반환된다.

async function getData() {
  const res = await fetch('https://example.com/api/data', { cache: 'force-cache' });
  return res.json();
}
  1. fetch렌더링 중에 옵션이 포함된 요청이 처음 'force-cache'호출되면 Next.js는 캐시된 응답이 있는지 데이터 캐시를 확인한다.
  2. 캐시된 응답이 발견되면 즉시 반환되고 메모화된다.
  3. 캐시된 응답이 없으면 데이터 소스에 요청이 이루어지고, 결과는 데이터 캐시에 저장되고 메모화된다.
  4. 캐시되지 않은 데이터(예: cache옵션이 정의되지 않았거나 를 사용하지 않음 { cache: 'no-store' })의 경우 결과는 항상 데이터 소스에서 가져와서 메모화된다.
  5. 데이터가 캐시되든 캐시되지 않든, 요청은 항상 메모화되어 React 렌더 단계 중에 동일한 데이터에 대한 중복 요청이 발생하지 않도록 한다.

✔️ On-demand Revalidation (주문형 재검증) 작동방식

next.revalidate 옵션을 사용하면 일정 시간마다 새로운 데이터를 가져오도록 설정할 수 있다.

async function getData() {
  const res = await fetch('https://example.com/api/data', { next: { revalidate: 60 } });
  return res.json();
}
  1. fetch() 요청이 처음 호출될 때, 외부 데이터 소스에서 데이터를 가져와 데이터 캐시(Data Cache) 에 저장된다.
  2. 주문형 재검증이 트리거되면 해당 캐시 항목이 캐시에서 제거된다 PURGE.
  3. 이는 시간 기반 재검증(Time-based Revalidation) 과는 다르다.
    • 시간 기반 재검증은 새로운 데이터가 가져와질 때까지 기존(오래된) 데이터를 유지하지만,
    • 주문형 재검증은 즉시 캐시를 무효화하고 새 데이터를 요청하도록 한다.
  4. 이후 동일한 요청이 발생하면 캐시 MISS가 발생하며, 외부 데이터 소스에서 다시 데이터를 가져와 데이터 캐시에 저장한다.

✔️ Data Cache 특징

  • 백엔드 서버로부터 불러온 데이터를 거의 영구적으로 보관하기 위해 사용된다.
  • 서버 가동중에는 영구적으로 보관된다.

✅ Full Route Cache (전체 경로 캐시)

Next.js는 정적 페이지(Static Pages)를 생성할 때 전체 페이지를 빌드 타임(또는 재검증 시)에 렌더링하고 캐싱하여 빠르게 제공할 수 있도록 한다. 이렇게 하면 매 요청마다 서버에서 다시 렌더링하는 대신 미리 캐싱된 경로를 제공할 수 있어 페이지 로딩 속도가 빨라진다.

✔️ Full Route Cache의 작동 방식

  1. 정적 경로가 생성될 때(Static Rendering)

    • Next.js는 HTMLRSC Payload를 서버 캐시에 저장
    • 이후 동일한 요청이 들어오면 캐시된 데이터를 즉시 반환
  2. 사용자가 페이지 요청

    • 정적 경로일 경우 → 캐시된 HTMLRSC Payload 반환 (SSG)
    • 동적 경로일 경우 → 서버에서 다시 렌더링 후 반환 (SSR)
  3. 데이터 재검증(Revalidation) 또는 배포 발생 (ISR )

    • 캐시가 무효화되며 새로운 요청 시 최신 데이터로 업데이트됨

즉, Full Route Cache는 SSG(정적 생성)된 페이지를 캐싱하고, SSR(동적 요청)된 페이지는 캐싱 없이 렌더링하며, ISR(점진적 재생성)된 페이지는 특정 조건에서 캐시를 업데이트하는 방식으로 동작한다.

✔️ Full Route Cache 특징

  • 정적 페이지(Static Pages)에만 Full Route Cache가 적용된다.
  • 빌드 타임(정적 생성 시) 또는 데이터 재검증(Revalidation) 후 페이지를 캐싱한다.
  • 배포 또는 데이터 재검증 시 캐시가 자동 삭제된다.

✅ Client Router Cache (클라이언트 라우터 캐시)

Next.js의 Client-side Router Cache는 경로 세그먼트(Route Segment)의 RSC 데이터를 클라이언트 메모리에 저장하여 성능을 최적화하는 기능이다.

✔️ Client-side Router Cache의 역할

사용자가 네비게이션할 때, Next.js는 방문한 경로 세그먼트를 캐싱하고 사용자가 이동할 가능성이 높은 경로를 미리 가져온다.

  • 즉각적인 뒤로/앞으로 탐색 (Instant Back/Forward Navigation)
  • 네비게이션 시 전체 페이지 새로고침 방지
  • React 및 브라우저 상태 유지

✔️ Router Cache에 저장되는 데이터

  • 레이아웃(Layouts): 네비게이션 시 캐싱 및 재사용 → 부분 렌더링(Partial Rendering)
  • 로딩 상태(Loading States): 캐싱 및 재사용 → 즉각적인 네비게이션 제공
  • 페이지(Pages): 기본적으로 캐시되지 않지만, 브라우저의 뒤로/앞으로 이동 시 재사용됨

✔️ Router Cache의 지속 시간

  • 네비게이션 중에는 유지되지만 페이지 새로고침 시 초기화됨
  • 특정 시간이 지나면 레이아웃과 로딩 상태의 캐시가 삭제됨
  • 무효화 기간은 리소스가 프리페칭(prefetching)된 방식과 정적으로 생성되었는지 여부에 따라 다름

📌 정리

구분Request MemoizationData CacheFull Route CacheClient Router Cache
설명동일한 요청이 같은 렌더링 패스에서 중복 실행되지 않도록 메모이제이션 (자동 캐싱)fetch() 요청을 캐싱하여 데이터 소스 요청을 줄임정적으로 생성된 페이지(HTML, RSC Payload)를 서버에서 캐싱클라이언트에서 네비게이션 시 경로 세그먼트를 캐싱
캐싱 위치서버 메모리 (렌더링 중 유지됨)서버 (데이터 저장)서버 (페이지 저장)클라이언트 (브라우저 메모리)
기본 캐싱 여부✅ 기본 활성화❌ (Next.js 15부터 no-store 기본값)✅ 기본 활성화 (정적 페이지)✅ 기본 활성화 (레이아웃, 로딩 상태)
데이터 보존 기간렌더링 종료 시 캐시 삭제서버가 동작하는 동안 지속배포 시 삭제되거나 재검증 시 업데이트세션 동안 유지되며, 페이지 새로고침 시 삭제
캐시 무효화 방법렌더링 패스가 끝나면 자동 삭제next.revalidate를 사용한 데이터 재검증 또는 cache: 'no-store' 설정배포 또는 revalidatePath() 호출router.refresh(), cookies.set(), cookies.delete() 호출
적용 대상React 렌더링 단계 내에서 동일한 요청API 요청(fetch) 응답 데이터정적으로 렌더링된 페이지네비게이션 중 이전 및 예상되는 경로
주요 특징- 하나의 페이지를 렌더링하는 동안 같은 fetch() 요청을 중복 실행하지 않음- fetch() 호출을 캐싱하여 데이터 요청 최적화
- cache: 'force-cache' 설정 필요
- 정적 페이지를 서버에서 캐싱하여 성능 최적화
- 배포 시 삭제됨
- 네비게이션 성능 개선
- 브라우저 상태 및 React 상태 유지
  • Request Memoization → 하나의 렌더링 패스 동안 동일한 요청을 자동으로 메모이제이션 (렌더링 완료 후 삭제됨)
  • Data Cache → API 요청(fetch) 응답 데이터를 캐싱하여 서버 부하 감소
  • Full Route Cache → 서버에서 정적 페이지를 캐싱하여 빠른 응답 제공
  • Client Router Cache → 클라이언트에서 네비게이션 성능을 향상 (세션 중 유지되며, 새로고침 시 삭제됨)


📚 Next.js 공식문서
🎥 한 입 크기로 잘라먹는 Next.js

0개의 댓글