Next 13의 App Router부터는 프론트서버의 부담이 많이 늘었다.
이에 캐싱 전략을 적절히 활용하지 않으면 서버가 과부하가 올 수가 있다.
따라서 Next에서는 4가지의 캐싱 전략을 제공한다.
Mechanism | What | Where | Purpose | Duration |
---|---|---|---|---|
Request Memoization | Return values of functions | Server | Re-use data in React Component tree | Per-request lifecycle |
Data Cache | Data | Server | Store data across user requests and deployments | Persistent (can be revalidated) |
Full Route Cache | HTML and RSC payload | Server | Reduce rendering cost and improve performance | Persistent (can be revalidated) |
Router Cache | RSC Payload | Server | Reduce server requests on navigation | User session or time-based |
Build Time
: 서비스를 배포할 때 (배포하기 직전에 압축하거나 등등..)Request Time
: 배포를 한 후에 실제 요청이 사용자로 부터 왔을 때
Next에서는 하나의 페이지
에서 동일한 fetch 요청이 여러개 있을 경우,
자동으로 요청을 압축해서 비효율적인 fetch를 최소화한다.
즉, 페이지를 처음에 렌더링 할 때 중복된 요청이 있으면 중복을 제거해주기 때문에, 다음번에 페이지를 방문할 땐 캐시들이 아예 초기화되어 데이터를 새로 불러온다.
Duration
: 캐시 지속기간Revalidating
: 언제 다시 새로운 캐시를 받아 올지Opting out
: 이 캐시를 사용하지 않게 설정페이지와 상관 없이 프론트 서버에서 백엔드 서버로 보낸 요청을 얼마나 오래 캐시할 것인지 설정한다.
기본적으로 캐싱이 되며, 한번 캐싱하면 이 값이 계속 유지 된다.
Revalidating
export async function getFollowingPosts() {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/followings`, {
next: {
revalidate: 3600, // 캐시 주기 설정, 1시간 후 새로운 데이터를 받아온다.
tags: ["posts", "followings"],
}
});
return res.json();
}
Time-based Revalidation
: 일정 시간이 지나면 자동으로 캐시를 갱신한다.
예시에 작성된 { revalidate: 3600 }
를 적용하면 캐시를 초단위로 적용할 수 있다.
On-demand Revalidation
: 개발자가 직접 코드로 캐시를 갱신한다.
예시에 작성된 { tags: ["posts", "followings"] }
를 서버에서 revalidateTag("posts")
와 같은 함수를 사용하여 revalidate할 수 있다.
예시
type Props = {
pageParam?: number;
};
export async function getPostRecommends({ pageParam }: Props) {
const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/followings`, {
next: {
tags: ["posts", "recommends"],
},
cache: "no-store", // 캐시 사용하지 않음
});
return res.json();
}
예시에 작성된 { cache: 'no-store' }
를 적용하면 데이터 캐시를 사용하지 않는다.
만약, 라이브러리에서 어떤 서버에 요청을 보내는 경우 그런 요청도 Next는 캐싱을 하는데. 캐시를 사용하지 않으려면 page.tsx 상단에 아래와 같이 작성한다.
export const dynamic = 'force-dynamic'
이렇게 작성하면 해당 페이지에서 보내는 모든 요청을 캐싱하지 않게 설정이 된다.
page.tsx를 빌드 타임에 얼마동안 캐시할지 설정한다.
페이지 내에 변하는 요소가 하나라도 있다면 다시 캐시를 받아오기 때문에 Full Route Cache가 제대로 동작되려면 페이지에 변하는 요소가 없어야 한다.
즉, 정적인 페이지를 설계할 때 의미있게 사용되는 캐시이다.
Duration
: 기본적으로 지속된다.Invalidation
cache: no-store
가 페이지 내에 하나라도 존재한다면 캐시되지 않는 부분(매번 새로운 데이터로 갱신)이 있는 것이기 때문에 사실상 Full Route Cache는 의미가 없다.Opting Out
: Dynamic Functions(cookies, headers, useSearchParams, searchparams)를 사용하거나 데이터 캐시를 Opting Out하면 Full Route Cache를 Opting Out 할 수 있다.Next에는 사용자 세션 동안 개별 경로 세그먼트로 분할된 React 서버 컴포넌트 페이로드를 저장하는 메모리 내 클라이언트 측 캐시가 있는데 이를 Router Cache라 한다.
Router Cache는 다른 페이지내 동일한 레이아웃을 갖는다면 해당 레이아웃을 캐싱한다.
Duration
: 페이지를 새로고침하기 전까지 계속 유지된다.prefetch={true}
를 추가한다. ex) Invalidation
Opting out
: Router Cache에서는 Opting out 할 수 없다.참고
Next + React Query로 SNS 서비스 만들기
Building Your Application: Caching | Next.js텍스트