본문 바로가기
FrontEnd/Next.js

아이템 리스트 페이지의 서버 컴포넌트를 최적화 시켜보기(fetch 캐싱 옵션)

by 위그든씨 2025. 9. 19.

사전 지식

next app router의 서버 컴포넌트에서 다이나믹한 요소 cookies, params, searchParams 등등을 사용하는 동작이 없다면 SSG로 동작하여 캐싱이 강제화 된다 -> fetch option [ force cache ] . 이때 next: revalidate 와 같은 주기를 등록한다면 이는 ISR로 동작하여 주기마다 캐시에 담긴 데이터를 최신화 시켜준다. 

fetch에 no-store 옵션을 명시한다면 이는 SSR 동작이 되어 요청 시점마다 서버에서 HTML을 생성해서 보내므로 SSG/ISR 보다 성능상 좋지 않다. 그래서 개인적으로 Next의 최적화를 생각하여 서버 컴포넌트는 될 수 있는 한 SSG/ISR로 할려고 노력하는 편이다. 

문제 상황

제목과 같이 아이템 리스트를 보여주는 페이지가 있을 경우 상단의 서버 컴포넌트에서는 fetch를 통해 네트워크 요청으로 디비에 담긴 데이터를 가져올 수 있을 것이다. 이 때 fetch의 캐싱 옵션으로 no-store를 준다면 클라이언트가 페이지에 접근 할 때마다 배포 서버에서는 HTML을 새로 생성해서 많은 사용자가 접근 할 경우, 배포 서버는 과부하를 겪을 것이다.

 이것을 최적화 하는 방법으론 fetch 의 캐싱 옵션을 사용하는 것이다. 캐싱 옵션을 명시하지 않는다면 서버 컴포넌트에서는 force-cache가 적용되어 빌드 시점에 데이터를 가져와서 html에 미리 포함 시킬 것이다. 이후 사용자들이 이 페이지에 접근하더라도 배포 서버에서는 이미 만들어진 HTML 을 보내기 때문에 배포 서버에 가해지는 부하는 SSR로 동작할 때보다 적을 것이다. 

여기에서 들 수 있는 의문은 운영자나 업자들이 새로운 아이템을 디비에 추가했을 경우 유저들은 이 아이템이 추가 된 리스트 페이지를 보냐는 것이다. 왜냐하면 SSG로 동작하여 빌드 시점에 만들어진 캐싱 된 아이템들만 페이지에 보여지기 때문이다. 이는 revalidatePath나 revalidateTag 를 활용하면 해결할 수 있다.. 이는 서버에서 동작하는 배포 서버 전체 캐시를 무효화 하는 동작이다.  운영자가 새로운 데이터를 디비에 등록 한 뒤 revalidatePath를 실행하는 코드를 심어놨다면, 이후 이 동작이 실행했을 경우 next는 이것을 캐치하여 배포 서버에서 기존에 빌드로 생성 된 HTML과 데이터 캐시를 삭제한 뒤 새로운 HTML을 생성하고 이때 디비로부터 새로운 아이템들을 받아와서 캐싱한다. 따라서 빌드 된 결과물이 바꼈으니 유저들이 아이템 리스트 페이지에 접근헀을 때는 아이템이 추가 된 페이지를 볼 수 있다. 

운영자 아이템 등록
   ↓
revalidatePath("/shop")
   ↓
Next.js: /shop 캐시 삭제
   ↓ (다음 요청 시점)
사용자 /shop 접속
   ↓
서버 컴포넌트 실행 + fetch("/api/shop/all")
   ↓
DB 최신값 가져옴
   ↓
Next.js 캐시에 저장 + 응답
   ↓
다음 사용자들은 이 캐시 활용

 

기존에도 POST 동작 후 성공하면 revalidatePath를 실행하고 router.refresh를 실행하여 새로운 아이템이 추가 된 리스트를 보여주도록 동작을 했지만 내부 로직을 정확히 알지 못하여 SSG/ISR+revalidatePath 와 같은 최적화 경험을 설명하지는 못했다. 그래서 이번 기회에 글을 작성해봄.

 

 

틀린 점은 피드백 해주면 감사하겠습니다