← 전체 글로 돌아가기

Next.js

Next.js fetch 캐시를 끄지 못해 관리자 화면만 늦게 바뀐 기록

관리자에서 글을 수정했는데 공개 화면보다 관리자 미리보기만 더 늦게 바뀌던 문제를 fetch 캐시 기준으로 좁혀 본 기록이다.

증상은 공개 화면이 아니라 관리자 화면에서 먼저 보였다

글을 저장한 뒤 /admin 목록으로 돌아오면 제목은 바뀌었는데 상세 미리보기에는 예전 excerpt가 남아 있었다. 이상했던 점은 공개 글 페이지를 새로 열면 최신 내용이 보였다는 것이다. 처음에는 DB 저장이 늦는 줄 알았는데, 같은 API를 curl로 호출하면 바로 새 값이 내려왔다.

헷갈린 지점은 "관리자 페이지니까 당연히 매번 새로 가져오겠지"라고 생각한 부분이었다. Next.js App Router에서는 서버 컴포넌트 안의 fetch도 기본 캐시 규칙을 타기 때문에, 관리자 화면이라고 해서 자동으로 동적 렌더링이 되는 것은 아니었다.

먼저 API 응답부터 분리해서 확인했다

브라우저에서만 보면 캐시인지 상태 관리 문제인지 구분이 잘 안 됐다. 그래서 저장 직후 같은 주소를 터미널에서 확인했다.

curl -s https://example.com/api/admin/posts/latest | jq '.title, .excerpt'

API가 최신 값을 돌려주면 DB와 라우트 핸들러는 일단 의심 목록에서 내려도 된다. 반대로 여기서도 예전 값이면 프론트 캐시를 보기 전에 저장 로직부터 봐야 한다.

수정한 기준

관리자 화면처럼 저장 직후 결과가 바로 보여야 하는 곳은 캐시 이득보다 혼란 비용이 더 컸다. 그래서 해당 fetch에만 캐시를 끄는 쪽으로 정리했다.

const res = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/admin/posts`, {
  cache: 'no-store',
});

페이지 전체가 항상 동적이어야 한다면 파일 상단에 아래처럼 명시하는 방법도 있다.

export const dynamic = 'force-dynamic';

다만 모든 페이지에 습관처럼 붙이지는 않았다. 공개 글 목록처럼 몇 분 늦어도 되는 화면은 revalidate를 쓰는 편이 더 낫다.

다시 안 겪으려고 남긴 점검 순서

  • 저장 직후 API를 직접 호출해서 DB 반영 여부를 본다.
  • 서버 컴포넌트 fetchcache, next.revalidate 옵션이 있는지 확인한다.
  • 관리자 페이지와 공개 페이지의 캐시 기준을 따로 정한다.
  • 배포 뒤에는 브라우저 새로고침만 믿지 말고 curl 결과를 같이 본다.

이번 문제는 코드 한 줄로 끝났지만, 원인은 "관리자 화면은 실시간일 것"이라는 가정이었다. 앞으로 수정 화면, 주문 화면, 알림 화면처럼 사용자가 방금 한 행동을 확인하는 페이지는 처음부터 no-store 여부를 체크리스트에 넣기로 했다.