본문으로 건너뛰기
개발 머꼬
개발 노트Next.js
hohyeon.dev61

뒤로 가기마다 목록을 서버에서 다시 받아 오던 이유 — staleTimes.dynamic의 기본값은 0초다

  • #Engineering Note
  • #Next.js
  • #Performance

문제 발생

목록에서 글을 열고 뒤로 가면 목록이 매번 서버에서 다시 그려졌습니다. 네트워크 탭에는 뒤로 가기마다 GET /posts 요청이 하나씩 찍혔고, 스크롤 위치도 흔들렸습니다. 서버 응답 자체는 20~40ms라 느린 곳은 서버가 아니었습니다.

이 앱의 페이지는 전부 동적입니다. 루트 레이아웃이 요청마다 세션을 읽어 헤더에 닉네임을 그리기 때문입니다.

원인 분석

동적 페이지는 클라이언트 라우터 캐시에 남지 않습니다. Next.js 문서의 staleTimes 설정을 보면 dynamic은 페이지가 정적으로 생성되지도, 완전히 프리페치되지도 않았을 때 쓰이는 값이고 기본값은 0초(캐시하지 않음) 입니다. 버전 이력에 v15.0.0에서 dynamic 기본값이 30초에서 0초로 바뀌었다고 적혀 있습니다.

0초라는 것은 라우터 캐시에 넣자마자 낡은 것으로 취급한다는 뜻입니다. 뒤로 가기는 캐시에서 세그먼트를 꺼내 쓰는 동작이라, 꺼낼 것이 없으니 서버에 다시 요청합니다.

레이아웃은 원래도 캐시되고 있었습니다. 문서는 이 설정이 부분 렌더링에 영향을 주지 않으며 공유 레이아웃은 매 내비게이션에서 자동으로 다시 가져오지 않는다고 말합니다. 다시 받아 온 것은 page 세그먼트(목록)뿐입니다.

해결 방안

  1. 동적 페이지의 유지 시간을 명시합니다. 값의 단위는 초입니다.
// next.config.ts
const nextConfig = {
  experimental: {
    staleTimes: { dynamic: 180 },
  },
};

180초는 "글 하나 읽고 돌아오는 시간"에서 나온 값입니다. 예전 기본값 30초는 글 하나 읽기에 대개 모자라 결국 다시 불러옵니다.

  1. 대가를 압니다. 그 시간 동안은 남이 그 사이에 쓴 글이 목록에 안 보입니다. 내가 한 변경은 Server Action 안의 revalidatePath/revalidateTag가 그 자리에서 무효화하므로 문제가 되지 않습니다.

  2. 로그아웃은 명시적으로 캐시를 버립니다. 로그인한 상태로 캐시된 세그먼트가 로그아웃 뒤에 보이면 안 됩니다. 로그아웃 액션이 리다이렉트 전에 revalidatePath("/", "layout")을 부릅니다.

  3. 서버·프록시 캐시와는 다른 물건입니다. 라우터 캐시는 탭 하나의 메모리이고 새로고침하면 사라집니다. nginx의 proxy_cacheCache-Control 판단과 섞지 않습니다.

  4. 실측으로 확인합니다. 설정 뒤 뒤로 가기에서 /posts 요청이 0건이고 스크롤이 유지되는지 네트워크 탭으로 봅니다. 문서의 static 기본값(5분)은 정적 페이지와 prefetch={true}인 링크에만 해당하니, 동적 페이지에서 그 값이 적용됐다고 착각하지 않습니다.

공식 문서

마지막 수정

좋아요북마크

댓글0

아직 댓글이 없어요. 첫 의견을 편하게 남겨 보세요.