본문 바로가기
C.W.K.
Stream
Lesson 02 of 09 · published

Next.js 15부터 fetch()는 기본 캐시가 아니야

~22 min · caching, v15, breaking change

Level 0호기심
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

기본값이 뒤집혔어

Next.js 14에서는 서버 컴포넌트의 fetch()가 기본적으로 캐시됐어. 의도를 밝히지 않은 요청이 오래된 데이터를 보여 주는 문제가 많았고, 15부터는 명시적으로 선택하지 않은 요청을 캐시하지 않는 쪽으로 바뀌었어.

원하는 전략설정
무효화할 때까지 캐시fetch(url, { cache: 'force-cache' })
N초마다 재검증하는 ISRfetch(url, { next: { revalidate: 60 } })
요청형 무효화를 위한 태그fetch(url, { next: { tags: ['posts'] } })
캐시하지 않음fetch(url) 또는 { cache: 'no-store' }
라우트 구간의 기본 재검증 시간export const revalidate = 60

업그레이드 뒤 느려졌다면 의도를 복원해

14에서 올린 앱이 갑자기 느려졌다면 모든 요청을 다시 캐시하기부터 하지 마. 매 렌더마다 최신일 필요가 없는 데이터만 골라 force-cacherevalidate를 붙여. 이전에는 묵시적으로 받던 캐시를 이제 요구사항에 맞게 선언하는 작업이야.

캐시는 정확성 계약이야

빠르게 만드는 옵션이기 전에, 사용자가 얼마나 오래된 값을 봐도 되는지를 정하는 계약이야. 캐시 여부와 수명을 코드 리뷰에서 설명할 수 없다면 아직 결정한 게 아니야.

각 fetch 옆에 신선도 문장을 적어 봐. “상품 설명은 한 시간 낡아도 된다”, “재고는 결제 직전에 다시 읽는다”처럼 제품 언어로 설명한 뒤 그 값을 revalidateno-store로 옮겨. 버전 업그레이드에서는 이전 캐시 동작에 우연히 기대던 라우트를 측정으로 찾아.

모든 요청을 force-cache로 되돌리면 성능은 회복돼 보여도 잘못된 값이 오래 남을 수 있어. 반대로 기본 no-cache를 그대로 두면 공개 콘텐츠까지 매 요청 계산해. 프레임워크의 기본값은 안전한 출발점이지 제품의 신선도 결정을 대신하는 답이 아니야. 시간이 표시되는 테스트 API를 fetch()하고 기본 호출, force-cache, no-store, revalidate의 연속 요청 결과를 비교해. 개발 모드가 아니라 production build에서 서버 로그와 응답 시간을 보고, 14에서 올린 라우트의 의도가 코드에 명시됐는지 확인해.

Code

버전별 기본값 변화·tsx
// v14 (사라짐)
const res = await fetch(url); // 기본값으로 캐시

// v15+ (현재)
const res = await fetch(url); // 캐시 안 됨 — 매 요청 새

// 명시적으로 다시 캐시 선택
const cached = await fetch(url, { cache: 'force-cache' });
const isr = await fetch(url, { next: { revalidate: 60 } });
const tagged = await fetch(url, { next: { tags: ['posts'] } });
라우트 단위 재검증·tsx
// app/blog/page.tsx
export const revalidate = 300; // 전체 라우트에 5분

export default async function BlogPage() {
  // 이 라우트 아래 모든 fetch가 기본값으로 300초마다 재검증
  const posts = await fetch('https://api.example.com/posts').then(r => r.json());
  return <PostList posts={posts} />;
}

External links

Exercise

한 시간마다 바뀌는 데이터를 읽는 fetch에 revalidate: 3600을 적용해. production 환경에서 후속 요청이 캐시를 쓰고 시간이 지난 뒤 갱신되는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.