1. 태그 기반 데이터 캐싱


Next.js App Router는 기본적으로 서버 컴포넌트에서 GET 요청으로 받아온 데이터를 영구 캐싱합니다. 이후 동일한 요청을 보낼 경우 캐싱된 데이터를 사용하기 때문에 서버 비용을 절약할 수 있습니다.

하지만 데이터 변동이 자주 발생해 최신화가 중요한 상황에서는 캐싱된 데이터와 최신 데이터 간 싱크가 맞지 않아 사용자에게 혼란을 야기할 수 있습니다. 예를 들어 Trablock에서는 다음과 같은 상황이 존재합니다.

<aside>

  1. 서버 측에서 페칭한 여행 계획(A)을 조회한다. [A 캐싱 | 서버 최신 데이터 = A]
  2. 작성자가 여행 계획을 수정(A’)한다. [서버 최신 데이터 = A’]
  3. 작성자가 다시 여행 계획을 조회한다. [캐싱된 데이터 A 사용] </aside>

위 상황에서 작성자가 수정된 여행 계획을 다시 조회했을 때, 작성자가 알고 있는 데이터 A’와 캐싱된 데이터 A가 서로 다르기 때문에 수정이 되지 않은 것으로 인식할 수 있습니다.

Next.js는 캐시를 제어하기 위해 태그 기반 시스템을 사용합니다.

<aside>

  1. tags: 캐시의 태그를 설정합니다.
fetch(`https://...`, { next: { tags: ['tag1', 'tag2'] } });
  1. revalidate: 캐시의 수명을 설정합니다.
fetch(`https://...`, { next: { revalidate: false | 0 | number } });
  1. revalidateTag: 특정 태그를 가진 캐시를 재검증합니다.
import { revalidateTag } from 'next/cache';

revalidateTag('tag1');

</aside>

2. 구현 및 적용


Trablock에서는 Fetch API에 다음과 같이 적용했습니다.

  1. 공통 태그, 고유 태그
// 공통 태그
const CACHE_TAGS_PREFIX = {
  ARTICLE: 'ARTICLE',
  ARTICLE_SCHEDULE: 'ARTICLE_SCHEDULE',
  USER_PROFILE: 'USER_PROFILE',
  GOOGLE_PLACES: 'GOOGLE_PLACES'
};

// [공통 태그, 고유 태그] 
const CACHE_TAGS = {
  ARTICLE: {
    getArticle: (articleId: number) => [CACHE_TAGS_PREFIX.ARTICLE, `getArticle-${articleId}`],
    // ...
};

공통 태그: 같은 카테고리 안에 속한 API에는 동일한 태그를 부여합니다. 동일한 공통 태그를 가진 모든 API에 대해 한번에 재검증할 수 있습니다.

고유 태그: 각 API에 대해 고유한 태그를 부여합니다. 만약 articleId처럼 동적 파라미터가 있을 경우, 해당 파라미터를 반영하여 태그를 생성합니다.

  1. revalidate 시간 프리셋