THE DEVLOG

scribbly.

Next JS 치트 시트

2025.05.10 19:29:11

 

1.00

확장된 fetch API

Next.js 15에서는 기본 fetch API를 확장하여 캐싱 및 재검증 동작을 세밀하게 제어할 수 있다. fetch 함수의 두 번째 인자로 next 옵션을 전달하여 다음과 같은 설정이 가능하다:

  • cache: 캐싱 전략 설정 ('force-cache', 'no-store' 등)
  • revalidate: 캐시된 데이터를 재검증하는 시간(초 단위)
  • tags: 캐시 태그를 지정하여 그룹화된 데이터의 재검증에 활용

예시:

const res = await fetch('https://api.example.com/data', {
  next: {
    cache: 'force-cache',
    revalidate: 3600,
    tags: ['example-data'],
  },
});

이 설정은 해당 요청의 응답을 1시간 동안 캐시하며, 'example-data' 태그를 통해 그룹화된 데이터의 재검증에 활용할 수 있다.

revalidateTag: 태그 기반의 온디맨드 재검증

revalidateTag 함수는 지정된 태그와 연관된 모든 캐시된 데이터를 무효화하여 다음 요청 시 최신 데이터를 가져오도록 한다. 이는 서버 액션이나 라우트 핸들러에서 호출할 수 있다.

예시:

// app/actions.ts

'use server';

import { revalidateTag } from 'next/cache';

export async function updateData() {
  // 데이터 업데이트 로직
  revalidateTag('example-data');
}

주의사항:

  • revalidateTag는 해당 태그와 연관된 경로를 다음에 방문할 때 캐시를 무효화한다.
  • 즉시 모든 경로를 재검증하지 않으며, 다음 방문 시에만 적용된다.
  • 태그는 문자열로 지정하며, 대소문자를 구분하고 256자 이하여야 한다.

revalidatePath: 경로 기반의 온디맨드 재검증

revalidatePath 함수는 특정 경로의 캐시를 무효화하여 다음 요청 시 최신 데이터를 가져오도록 한다. 이 함수도 서버 액션이나 라우트 핸들러에서 호출할 수 있다.

예시:

// app/actions.ts

'use server';

import { revalidatePath } from 'next/cache';

export async function updatePage() {
  // 페이지 업데이트 로직
  revalidatePath('/example/path');
}

옵션:

  • path: 재검증할 경로를 문자열로 지정
  • type (선택): 'page' 또는 'layout'을 지정하여 해당 유형의 경로를 재검증

주의사항:

  • revalidatePath도 해당 경로를 다음에 방문할 때 캐시를 무효화한다.
  • 동적 경로의 경우, 정확한 경로를 지정해야 한다.

캐싱 기본 동작 변경

Next.js 15에서는 캐싱의 기본 동작이 변경되었다:

  • GET 메서드를 사용하는 라우트 핸들러는 기본적으로 캐시되지 않는다.
  • 명시적으로 캐싱을 설정하려면 export const dynamic = 'force-static'과 같은 구성을 사용해야 한다.

예시:

// app/api/data/route.ts

export const dynamic = 'force-static';

export async function GET() {
  // 데이터 반환 로직
}

요약

  • 확장된 fetch API를 통해 캐싱 및 재검증을 세밀하게 제어할 수 있다.
  • revalidateTagrevalidatePath를 사용하여 태그 또는 경로 기반의 온디맨드 재검증이 가능하다.
  • Next.js 15에서는 GET 라우트 핸들러의 캐싱이 기본적으로 비활성화되어 있으며, 명시적으로 설정해야 한다.

CDN 캐시와 연산 캐시

CDN 캐시 (Content Delivery Network Cache)

  • 정의: 최종 HTML, 이미지, JSON 응답 등을 지리적으로 분산된 서버(CDN)에서 캐싱하여 사용자에게 가까운 위치에서 빠르게 서빙하는 방식이다.

  • Next.js에서 사용 예시:

    • fetch(url, { next: { revalidate, tags } })
    • export const dynamic = 'force-static'
    • SSG, ISR 기반 페이지
  • 특징:

    • 클라이언트 요청 → Vercel CDN → 캐시 hit 시 백엔드까지 가지 않음
    • X-Vercel-Cache: HIT 헤더로 확인 가능
    • revalidateTag, revalidatePath로 무효화 가능
  • 장점:

    • 매우 빠름 (백엔드 연산 없이 전달)
    • 글로벌 사용자에게 일관된 성능 제공
  • 단점:

    • 정적 리소스에 적합
    • 사용자 인증이 필요한 컨텐츠에는 부적합

서버 연산 캐시 (Function-level Cache)

  • 정의: 데이터베이스 쿼리, 복잡한 연산 결과 등을 서버에서 일정 시간 저장하고, 다음 요청부터는 연산을 생략하는 방식이다.

  • Next.js에서 사용 예시:

    • unstable_cache(async () => { ... }, key, { revalidate })
  • 특징:

    • fetch 없이도 캐싱 가능 (DB 연산, JSON 변환, 복합 연산 포함)
    • 서버 빌드 타임 또는 런타임에서 저장됨
    • 클라이언트가 직접 접근 불가
  • 장점:

    • 연산 비용 절감
    • API 응답이나 HTML에 사용되지 않아도 캐시 활용 가능
  • 단점:

    • 캐시 위치가 CDN이 아니므로 지연시간은 약간 있음
    • Vercel 이외 환경에서는 제한적
비교 항목CDN 캐시서버 연산 캐시 (unstable_cache)
적용 위치Vercel 엣지 서버SSR 서버 또는 Edge Functions 내부
대상HTML, JSON, 이미지, fetch 결과함수 실행 결과, DB 쿼리 결과
캐시 무효화 방법revalidateTag, revalidatePathrevalidateTag, revalidatePath
TTL 설정revalidate: numberrevalidate: number
사용 용도외부에 노출되는 페이지/데이터내부 연산 최적화, 서버 자원 절약
인증 데이터❌ 기본적으로 부적합⭕ 접근 제어된 데이터 처리 가능
의존성URL에 종속키(key)와 파라미터에 종속
  • 정적 API 응답이나 HTML 페이지
    fetch + next.revalidate + CDN 캐시
  • DB 쿼리, 복잡한 비즈니스 로직 연산 결과 캐싱
    unstable_cache로 연산 자체를 줄이는 방향
  • 로그인 사용자 전용 데이터, 세션 기반 처리
    → 캐시 없이 SSR 또는 no-store fetch 사용 (또는 edge 캐시 우회)

unstable_cache()

unstable_cache는 Next.js 내부에서 제공하는 서버 측 캐싱 함수로, 주로 데이터 페칭 함수에 적용하여 정적으로 서버에서 캐싱된 결과를 반환하도록 한다. 이름에 unstable이 포함되어 있지만, 실제로는 작동한다.

사용 예

import { unstable_cache } from 'next/cache'

const getUserData = unstable_cache(
  async (userId: string) => {
    const res = await fetch(`https://api.example.com/users/${userId}`)
    return res.json()
  },
  ['user-data'],
  { revalidate: 3600 }
)

  • 첫 번째 인자: 캐시할 함수
  • 두 번째 인자: 캐시 키(key). 함수 인자 기반으로 캐시를 구분하려면 포함시켜야 함
  • 세 번째 인자: { revalidate: number; tags?: string[] } 옵션

이 함수를 통해 서버에서 주기적으로 데이터가 재검증되고, SSR 중 재사용이 가능해진다.

fetch()의 캐시 옵션과의 차이점

항목fetch() with next 옵션unstable_cache()
적용 대상HTTP 요청 (URL 기반)일반 함수 또는 fetch 함수
캐시 저장 위치Vercel CDN 또는 Edge Runtime서버 빌드 환경의 캐시 스토리지
키 결정 방식요청 URL + next.tags명시적인 키(key[])
주 용도외부 API 응답 캐싱DB 쿼리/로직 결과 자체 캐싱
호출 방식매번 요청될 수 있음캐시 히트 시 함수 자체 호출 생략
캐시 무효화revalidateTag, revalidatePath동일하게 사용 가능 (tags 제공 시)
경고 사항클라이언트에서 호출 시 next 옵션 무시클라이언트에서는 사용 불가 (서버 전용)

정리

  • fetch()HTTP 요청을 캐싱할 수 있는 기능이다. 주로 외부 API 응답을 그대로 가져올 때 유용하다.
  • unstable_cache()함수의 실행 결과를 캐싱하며, fetch 외의 연산 결과도 저장할 수 있다. 특히 DB 쿼리나 복잡한 서버 연산을 반복 실행하지 않게 할 때 유용하다.
  • 둘 다 revalidate, tags를 통해 캐시 생명주기를 제어할 수 있으며, revalidateTag 등을 통해 수동 무효화도 가능하다.
  • CDN 레벨에서의 퍼포먼스를 고려한다면 fetch + CDN 캐시가 더 적합하고, 서버 연산 최소화에 초점을 둔다면 unstable_cache()가 더 적합하다.