[Next.js] Full Route Cache, 페이지 자체를 캐싱하는 메커니즘

Woonil·2025년 12월 30일

Next.js

목록 보기
6/8

Full Route Cache는 한 마디로 ‘페이지 자체를 캐싱하는 것’이라 할 수 있다.

Next 서버 측에서 빌드 타임에 특정 페이지의 렌더링 결과를 캐싱하는 기능이다. 빌드 시에 Request Memoization와 Data Cache를 거쳐 반환된 특정 경로에 대한 페이지를 Full Route Cache로 저장하는 것이다. 이후 같은 경로의 페이지에 접속 요청이 생기면, Full Route Cache가 HIT 되어 캐시된 페이지를 브라우저에 반환한다(Pages Router의 SSG 방식의 렌더링과 유사하게 동작한다고 할 수 있다). 이를 통해, 요청이 오면 캐시된 결과를 즉시 반환하여 응답 속도를 크게 높일 수 있다.

🤔개념

페이지 분류 (서버 컴포넌트에만 해당)

Full Route Cache는 Static Page에만 적용된다. 이때, Static Page는 기본적으로 Dynamic Page가 아닌 경우의 페이지에 해당한다.

Dynamic Page

  • 특정 페이지가 접속 요청을 받을 때마다 매번 변화가 생기거나 데이터가 달라지는 경우
    • 캐시되지 않는 Data Fetching을 사용하는 경우
      async function ServerComponent() {
      	const response = await fetch("..."); // 또는 no-store 옵션 있는 경우
      	return <div>...</div>;
      }
  • 동적 함수(쿠키, 헤더, 쿼리 스트링)을 사용하는 컴포넌트가 존재하는 경우
    • 쿠키를 사용하는 경우
      import { cookies } from "next/headers";
      
      async function ServerComponent() {
      	const cookieStore = cookies();
      	const theme = cookieStore.get("theme");
      	
      	return <div>...</div>;
      }
    • 쿼리스트링을 사용하는 경우
      async function Page({ searchParams }: { searchParams: { q: string }}) {
      	const q = searchParams.q;
      	
      	return <div>...</div>;
      }
동적 함수 (쿠키,헤더,쿼리스트링)데이터 캐시페이지 분류
YESNODynamic Page
YESYESDynamic Page
NONODynamic Page
NOYESStatic Page

결론적으로, Full Route Cache를 적용할 수 있는 Static Page로 페이지를 구성하는 것이 권장된다. 물론, Dynamic Page를 사용해야 하는 경우에도 Request Memoization, Data Cache는 유효하므로 각각 경우에 맞게 최적화할 수 있다.

아래의 예시의 경우, 쿼리 스트링을 가져와서 사용자와 동적으로 상호작용해야 하므로, 해당 컴포넌트에서는 Static Page로 만들 수 없으며 Full Route Cache를 적용할 수 없다. 따라서 Data Cache를 적용하는 것이 최선이다.

  • Static Page로 만들 수 없는 경우 예시
    export default async function Page({
      searchParams,
    }: {
      searchParams: Promise<{ q?: string }>;
    }) {
      const resolvedSearchParams = await searchParams;
      const response = await fetch(
        `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/search?q=${resolvedSearchParams.q}`,
        { cache: "force-cache" }
      );
    
      if (!response.ok) {
        return <div>에러가 발생했습니다.</div>;
      }
      const books: BookData[] = await response.json();
    
      return (
        <div>
          {books.map((book) => (
            <BookItem key={book.id} {...book} />
          ))}
        </div>
      );
    }

Invalidation

Full Route Cache를 무효화하는 방법은 두 가지가 있다.

  • revalidation: Data Cache를 재검증하면, 오래된(stale한) 데이터 대신 fresh한 데이터를 불러온다. 따라서 서버에서 컴포넌트를 새로운 데이터를 기반으로 다시 렌더링하고 새 렌더링 출력을 캐시하여 Router Cache를 무효화한다(page router의 ISR 방식의 렌더링과 유사하게 동작한다고 할 수 있다).
  • 재배포: 배포 간에 지속되는 Data Cache와 달리 Full Route Cache는 새 배포 시 지워진다.

generateStaticParams

쿼리 파라미터를 갖는 상세 페이지의 경우, 동적으로 경로를 가져와야 하지만 Next가 제공하는 generateStaticParams 함수를 통해 지정한 쿼리 파라미터의 값을 가지는 페이지를 빌드 타임에 미리 생성할 수 있다. 따라서 이 함수는 Pages Router의 getStaticPaths 와 유사한 기능을 하는 함수라 할 수 있다.

export function generateStaticParams() {
  return [{ id: "1" }, { id: "2" }, { id: "3" }]; // 값은 문자열로 지정해야 함
}

export default async function Page({
  params,
}: {
  params: Promise<{ id?: string }>;
}) {
  const resolvedParams = await params;
  const response = await fetch(
    `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/${resolvedParams.id}`
  );
  if (!response.ok) {
    return <div>에러가 발생했습니다.</div>;
  }

  return (<></>);
}

Next.js는 generateStaticParams 에 지정하지 않은 페이지에 대해서도 실시간으로 캐싱을 진행한다. 특정 상세 페이지 재접속 시 네트워크 응답 속도가 108ms->21ms 로 감소한 것을 확인할 수 있다.

  • 초기 접속

  • 재접속

dynamicParams

만약, generateStaticParams 에 명시하지 않은 페이지의 경우 모두 NotFound 페이지로 보내고 싶을 수도 있다. 이러한 경우에는 dynamicParams 의 값을 false 로 지정하면 된다.

export const dynamicParams = false;

export function generateStaticParams() {
  return [{ id: "1" }, { id: "2" }, { id: "3" }];
}

Route Segment Config

dynamic

페이지의 유형을 강제할 수 있다. 페이지 상단에 export const dynamic = "옵션명" 형식으로 사용 가능하다.

옵션명설명
auto최초 요청에 대해 서버에서 새로 생성, 이후 요청에 대해 캐시된 페이지를 사용
force-dynamic페이지를 강제로 Dynamic Page로 설정
force-static페이지를 강제로 Static Page로 설정
error페이지를 강제로 Static Page로 설정 (설정하면 안되는 이유를 빌드 오류로 표시) 에러 발생 시 캐시된 페이지를 사용

클라이언트 라우터 캐시

브라우저에 저장되는 캐시로, 페이지 이동을 효율적으로 진행하기 위해 페이지의 일부 데이터를 보관한다. 페이지 이동 시 공통적으로 사용되는 레이아웃 컴포넌트 등의 RSC Payload 데이터를 캐시한다. 이를 통해 페이지 전환 시 불필요한 데이터 요청 없이 캐시된 레이아웃을 재사용하여 빠르게 화면을 구성할 수 있다.

참고자료
한 입 크기로 잘라먹는 Next.js (이정환)

profile
무엇이든 최선을 다하고자 노력합니다:)

0개의 댓글