2025-05-22
Next.js의 unstable_cache
를 사용하다가 아래와 같은 에러를 처음 마주했습니다.
Error: Route /roadmap/[externalId] used "headers" inside a function cached with "unstable_cache(...)". Accessing Dynamic data sources inside a cache scope is not supported. If you need this data inside a cached function use "headers" outside of the cached function and pass the required dynamic data in as an argument.
unstable_cache
안에서는 headers()
, cookies()
같은 dynamic api
를 쓸 수 없다는 경고입니다.
Next.js는 unstable_cache
내부에서 실행된 함수의 결과를 정적으로 캐시합니다. 그런데 headers()
처럼 매 요청마다 바뀔 수 있는 동적 데이터를 사용하면, 결과가 사용자마다 달라질 수 있어서 캐시의 의미가 사라지게 됩니다.
Accessing dynamic data sources such as headers or cookies inside a cache scope is not supported. If you need this data inside a cached function use headers outside of the cached function and pass the required dynamic data in as an argument.
https://nextjs.org/docs/app/api-reference/functions/unstable_cache
pickroad의 상세 페이지에서는 하나의 로드맵을 보여주면서 아래 정보를 같이 표시해야 했습니다.
처음엔 세션 처리를 위해 unstable_cache
사용을 포기할까도 고민했지만, 트래픽이 많아질 것을 고려하면 정적 데이터는 반드시 캐시해야 한다는 판단이 들었습니다. 그래서 정적 데이터와 동적 데이터를 분리해서 처리하는 방식을 선택했습니다.
공통적으로 모든 사용자에게 동일하게 제공되는 정적 데이터는 unstable_cache
를 활용해 효율적으로 캐싱했습니다.
반면, 사용자마다 달라지는 좋아요 여부나 북마크 상태와 같은 맞춤형 정보는 함수 외부에서 세션을 조회해 처리한 뒤, 그 결과를 바탕으로 동적으로 추가하여 반환하는 방식으로 분리해서 구현했습니다.
export const getRoadmap = unstable_cache(
async (externalId: Roadmap["externalId"]): Promise<Roadmap | null> => {
const roadmap = await db.query.roadmaps.findFirst({
where: eq(roadmaps.externalId, externalId),
with: {
category: true,
author: true,
},
});
if (!roadmap) return null;
return roadmap
},
);
export const getRoadmapWithSession = async (
externalId: Roadmap["externalId"],
): Promise<Roadmap | null> => {
const session = await auth.api.getSession({
headers: await headers(),
});
const roadmap = await getRoadmap(externalId);
if (!roadmap) return null;
let isLiked = false;
let isBookmarked = false;
if (session) {
const row = ... //like,bookmark여부 조회 query
isLiked = row.isLiked || false;
isBookmarked = row.isBookmarked || false;
}
return {
...roadmap,
isLiked,
isBookmarked,
};
};