본문 바로가기

개발 & IT/프론트엔드

Next.js 캐싱의 기본값과 동적 렌더링 전환 조건

Next.js의 렌더링 기본값

Next.js 공식 문서(Glossary)는 다음과 같이 명시한다.

Prerendering is the default for components that don't use Request-time APIs.

즉, Request-time API를 사용하지 않는 컴포넌트는 기본적으로 빌드 시점에 HTML을 생성해 캐싱한다.

dynamic 옵션의 기본값인 'auto'에 대한 설명도 같은 방향이다.

The default option to cache as much as possible without preventing any components from opting into dynamic behavior.

기본값이 "최대한 캐싱"이라는 것은 Next.js의 설계 방향을 직접적으로 보여준다.


Request-time API란

공식 문서(Glossary)는 Request-time API를 다음과 같이 정의한다.

Functions that access request-specific data, causing a component to opt into dynamic rendering.

해당하는 함수 목록은 다음과 같다.

  • cookies() — 요청 쿠키 접근
  • headers() — 요청 헤더 접근
  • searchParams — URL 쿼리 파라미터 접근
  • draftMode() — 드래프트 모드 접근

이 중 하나라도 layout 또는 page에서 사용되면 해당 라우트는 동적 렌더링으로 전환된다.


주의: cookies()는 렌더링 경로에서 실제 실행되어야 한다

cookies.md는 다음과 같이 명시한다.

Using it in a layout or page will opt a route into dynamic rendering.

여기서 "in a layout or page"는 파일 안에 직접 작성해야 한다는 의미가 아니다. 해당 layout/page의 렌더링 과정에서 실제로 실행되어야 한다는 뜻이다.

따라서 page.tsx가 유틸리티 함수를 호출하고, 그 안에서 cookies()가 실행된다면 원칙적으로 해당 라우트는 동적 렌더링 대상이 된다. 호출 위치보다 렌더링 경로에서 실제로 실행되는지 여부가 기준이다.

만약 cookies()를 사용했음에도 페이지가 정적으로 동작한다면, 원인은 다른 곳에 있을 가능성이 높다.

  • 빌드/렌더링 시점에 해당 함수가 실제로 호출되지 않았거나
  • dynamic = 'force-static' 같은 설정이 명시되어 있거나
  • cache() 또는 다른 캐싱 레이어와 섞여 의도와 다르게 동작했거나
  • fetch 캐싱 설정 때문에 응답이 정적으로 보이는 경우

결과적으로 페이지가 동적 신호를 받지 못하면 빌드 시점에 HTML이 생성되고 Full Route Cache에 저장된다. 이후 요청에서는 캐싱된 HTML이 반환되며, 서버 코드는 실행되지 않는다.


Full Route Cache란

Full Route Cache는 서버에서 렌더링한 페이지 전체의 HTML 결과물을 캐싱하는 계층이다. 이 캐시에 저장된 페이지는 요청마다 서버 컴포넌트를 실행하지 않고 저장된 결과를 즉시 반환한다.

Data Cache(개별 fetch 응답 캐싱)와는 별개의 계층이다.

캐시 계층 단위 서버 코드 실행 여부
Full Route Cache 페이지 전체 HTML 실행 안 됨
Data Cache 개별 fetch 응답 실행됨

Full Route Cache가 적용된 페이지는 서버 로그도 출력되지 않고, 데이터도 갱신되지 않는다.


해결: fetch에 cache: 'no-store' 명시

caching-without-cache-components.md에서 dynamic = 'force-dynamic'은 다음과 동일하다고 설명한다.

Setting the option of every fetch() request in a layout or page to { cache: 'no-store', next: { revalidate: 0 } }

fetchcache: 'no-store'를 명시하면 Next.js가 해당 라우트를 동적으로 처리한다.

Next.js는 전역 fetch를 자체 버전으로 교체하기 때문에, 유틸리티 함수 내부에서 호출된 fetch도 감지 가능하다. fetchno-store는 호출 위치와 무관하게 렌더링 경로 어디서든 전역으로 감지된다.


정리

상황 Full Route Cache 적용 여부
Request-time API를 page/layout에서 직접 사용 제외 (동적)
Request-time API가 렌더링 경로에서 실제로 실행됨 제외 (동적)
렌더링 경로에서 cookies() 등이 실행되지 않음 적용 (정적으로 판단)
fetch에 cache: 'no-store' 명시 제외 (동적)
connection() 호출 제외 (동적)

Next.js의 기본값은 "cache as much as possible"이다. 인증 기반의 동적 데이터를 다루는 페이지라면, 위 조건 중 하나를 명시적으로 충족시켜야 의도한 대로 동작한다.

반응형