Route Segment Config
Next.js 15에서는 각 layout.tsx
, page.tsx
, route.ts
파일에서 export하는 설정값들을 통해 해당 세그먼트의 동작 방식을 세밀하게 제어할 수 있다. 이는 기존의 getStaticProps
, getServerSideProps
모델보다 더 세분화된 캐싱 및 렌더링 제어가 가능하게 해준다.
Route Segment Config는 Next.js에서 개발중인
dynamicIO
기능으로 대체될 예정
설정 가능한 옵션 목록
옵션명 | 타입 | 기본값 |
---|---|---|
experimental_ppr | boolean | 없음 |
dynamic | 'auto' | 'force-dynamic' | 'error' | 'force-static' | 'auto' |
dynamicParams | boolean | true |
revalidate | false | 0 | number | false |
fetchCache | 'auto' | 'default-cache' | 'only-cache' | 'force-cache' | 'force-no-store' | 'default-no-store' | 'only-no-store' | 'auto' |
runtime | 'nodejs' | 'edge' | 'nodejs' |
preferredRegion | 'auto' | 'global' | 'home' | string[] | 'auto' |
maxDuration | number | 배포 플랫폼에서 설정 |
주요 옵션
dynamic
해당 세그먼트를 정적으로 렌더링할지, 동적으로 렌더링할지를 설정한다.
export const dynamic = 'auto'
값 | 설명 |
---|---|
'auto' | 가능한 한 정적으로 캐싱하되, 동적 API가 사용되면 자동으로 동적 렌더링으로 전환한다. |
'force-dynamic' | 항상 SSR로 처리한다. fetch마다 { cache: 'no-store', next: { revalidate: 0 } } 로 설정한 것과 같다. |
'error' | 동적 API를 사용하면 에러를 발생시킨다. 캐싱만 허용. getStaticProps 와 유사. |
'force-static' | 정적 렌더링을 강제한다. cookies() , headers() , useSearchParams() 는 빈 값을 반환한다. |
🧠 참고:
'error'
나'force-static'
을 사용하면dynamicParams
는 기본값이false
로 바뀐다.
export const dynamic = 'auto'인 경우:
Next.js는 정적 추론을 시도한다. fetch 요청이 모두 force-cache 등 정적 캐싱이면 정적 페이지로 처리하고 CDN에 저장한다.
dynamic = 'force-static':
완전한 정적 페이지로 간주. HTML, JSON, Static Asset이 Vercel CDN에 올라가고 변경 전까지는 그대로 유지된다.
dynamic = 'force-dynamic':
매 요청마다 서버에서 SSR 처리. CDN 캐시 없이 항상 fresh한 응답.
revalidate = 60:
CDN에 저장된 정적 페이지라도 60초마다 서버에서 다시 생성 가능함 (ISR). 이때 새 HTML이 생성되면 CDN도 새 것으로 덮어쓴다.
generateStaticParams
export async function generateStaticParams() {
return [{ slug: 'example' }, { slug: 'another' }]
}
- 동적 세그먼트에 대한 정적 경로 목록을 정의한다.
- 빌드 타임에 static page를 생성하며, 이외는 런타임에 생성됨.
dynamicParams
동적 세그먼트에 대해 generateStaticParams
에 포함되지 않은 경우의 동작을 결정한다.
export const dynamicParams = true
값 | 설명 |
---|---|
true | 포함되지 않은 세그먼트는 런타임에 생성된다. |
false | 해당 경로는 404를 반환한다. |
🧠 참고:
getStaticPaths
의fallback
옵션을 대체한다.generateStaticParams()
가 빈 배열을 반환하면, 경로 방문 시 최초 1회만 static render된다.dynamic = 'error'
일 경우 자동으로false
로 바뀐다.
revalidate
페이지 또는 레이아웃의 기본 revalidate 주기를 설정한다.
export const revalidate = 3600 // 1시간
값 | 설명 |
---|---|
false | 영구 캐싱 (Infinity) |
0 | 항상 동적 렌더링 |
숫자 | 초 단위로 revalidate 주기 지정 |
🧠 참고:
revalidate = 60 * 10
은 안 되고revalidate = 600
처럼 정적 분석 가능한 값이어야 한다.runtime = 'edge'
일 때는 사용 불가.- 개발 모드에서는 항상 동적으로 렌더링됨.
fetchCache
모든 fetch 요청의 기본 캐시 동작을 지정한다.
export const fetchCache = 'force-cache'
값 | 의미 |
---|---|
'auto' | 알아서 처리 |
'default-cache' | 기본 캐싱 동작 사용 |
'only-cache' | 캐시된 데이터만 사용, 미스 시 실패 |
'force-cache' | 강제로 캐싱 |
'force-no-store' | 강제로 비캐싱 |
'default-no-store' | 기본 비캐싱 동작 사용 |
'only-no-store' | 캐시된 데이터 무시하고 항상 네트워크 요청 |
dynamicIO
: 동적 데이터 기본 설정
dynamicIO
는 Next.js 15에서 도입된 실험적 기능으로, App Router에서의 데이터 페칭을 기본적으로 프리렌더링에서 제외시킨다. 즉, 명시적으로 캐시되지 않은 데이터는 항상 런타임에 새로 페칭된다.
dynamicIO
를 활성화하려면 next.config.ts
파일의 experimental
섹션에 다음과 같이 설정한다:
// next.config.ts
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
experimental: {
dynamicIO: true,
},
};
export default nextConfig;
'use cache'
: 명시적인 캐싱 지시어
'use cache'
지시어는 특정 라우트, 컴포넌트, 또는 함수의 결과를 캐시하도록 명시하는 역할을 한다. 이 지시어를 사용하면 해당 부분의 데이터가 캐시된다.
- 파일 수준 캐싱: 파일 상단에
'use cache'
를 추가하여, 해당 파일 내의 모든 익스포트를 캐시한다.
// app/page.tsx
'use cache';
export default async function Page() {
const data = await fetchData();
return <div>{data}</div>;
}
- 컴포넌트 수준 캐싱: 컴포넌트 내에서
'use cache'
를 사용하여, 해당 컴포넌트의 결과를 캐시한다.
export async function MyComponent() {
'use cache';
const data = await fetchData();
return <div>{data}</div>;
}
- 함수 수준 캐싱: 특정 함수 내에서
'use cache'
를 사용하여, 해당 함수의 반환값을 캐시한다.
export async function getData() {
'use cache';
const response = await fetch('/api/data');
return response.json();
}
캐시된 함수의 반환값은 직렬화 가능해야 하며, 비직렬화 가능한 인자나 props는 캐시 키에 포함되지 않다. 또한, 기본적으로 서버 측 캐시는 15분마다 재검증되며, cacheLife
와 cacheTag
API를 사용하여 캐시의 수명을 조정하거나 태그를 지정할 수 있다.
cacheLife
: 캐시 수명 설정
cacheLife
함수는 캐시된 데이터의 수명을 설정하는 데 사용된다. 이를 통해 데이터가 얼마나 오래 캐시되어야 하는지를 제어할 수 있다.
사용 예시:
import { unstable_cacheLife as cacheLife } from 'next/cache';
export async function getData() {
'use cache';
cacheLife('hours'); // 캐시 수명을 'hours'로 설정
const response = await fetch('/api/data');
return response.json();
}
cacheLife
는 'seconds'
, 'minutes'
, 'hours'
, 'days'
, 'weeks'
, 'max'
와 같은 문자열 값을 받아 캐시 수명을 설정한다. 또한, next.config.ts
파일에서 커스텀 캐시 프로파일을 정의하여 더 세밀한 제어가 가능하다.(Next.js)
예를 들어, next.config.ts
에서 다음과 같이 설정할 수 있다:
// next.config.ts
const nextConfig = {
experimental: {
dynamicIO: true,
cacheLife: {
categories: {
stale: 1800, // 클라이언트에서 30분 동안 캐시된 데이터 사용
revalidate: 600, // 서버에서 10분마다 데이터 재검증
expire: 86400, // 1일 후 캐시 만료
},
},
},
};
이후, 함수 내에서 cacheLife('categories')
를 호출하여 해당 프로파일을 적용할 수 있다.
cacheTag
: 캐시 태그 지정 및 무효화
cacheTag
함수는 캐시된 데이터에 태그를 지정하여, 특정 태그를 가진 캐시를 선택적으로 무효화하거나 재검증할 수 있도록 한다.
사용 예시:
import { unstable_cacheTag as cacheTag } from 'next/cache';
export async function getCategories() {
'use cache';
cacheTag('categories-data'); // 'categories-data' 태그 지정
const response = await fetch('/api/categories');
return response.json();
}
이후, 서버 액션이나 API 라우트에서 revalidateTag
를 호출하여 해당 태그를 가진 캐시를 무효화할 수 있다:
import { revalidateTag } from 'next/cache';
export async function revalidateCategories() {
revalidateTag('categories-data'); // 'categories-data' 태그를 가진 캐시 무효화
}
이를 통해, 예를 들어 관리자 패널에서 새로운 카테고리를 추가하거나 기존 카테고리를 수정한 후, 해당 캐시를 즉시 무효화하여 최신 데이터를 반영할 수 있다.
요약
기능 | 설명 |
---|---|
dynamicIO | 데이터 페칭을 기본적으로 런타임에 수행하도록 설정하는 실험적 기능. |
'use cache' | 특정 라우트, 컴포넌트, 또는 함수의 결과를 캐시하도록 명시하는 지시어. |
cacheLife | 캐시의 수명을 설정하여, 일정 시간 후에 자동으로 재검증되도록 한다. |
cacheTag | 캐시에 태그를 지정하여, 특정 태그의 캐시를 무효화하거나 재검증할 수 있다. |
dynamicIO
의 도입과 Route Segment Config의 대체
dynamicIO
는 Next.js 15의 실험적 기능으로, 다음과 같은 방향으로 기존 Route Segment Config의 역할을 함수/컴포넌트 수준에서 재정의한다:
dynamic
→ 제거됨
export const dynamic = ...
은 더 이상 권장되지 않으며, 대신 함수나 컴포넌트 안에서 직접'use cache'
,'use dynamic'
등을 선언함.
// 예시
export default async function Page() {
'use dynamic'; // 과거의 'force-dynamic'과 동일
const data = await fetchData();
return <div>{data}</div>;
}
revalidate
→ cacheLife
로 대체
export const revalidate = 60
같은 방식은cacheLife()
함수로 대체되어, 코드 내부에서 세밀하게 설정 가능.
import { unstable_cacheLife as cacheLife } from 'next/cache';
export async function Page() {
'use cache';
cacheLife('minutes'); // 또는 cacheLife(60)
...
}
fetchCache
→ 제거됨
fetchCache
는 이제 무의미. 대신'use cache'
와cacheLife()
가 이를 대체하고, fetch 자체는 명시적으로 설정 필요 없음.
dynamicParams
→ 무시됨
generateStaticParams()
와 관련된dynamicParams
설정도 사실상 무시됨. 동적 세그먼트에 대한 캐싱은use cache
여부로만 결정됨.
dynamicIO
가 Route Segment Config를 대체하는 방식
기존 Config | dynamicIO 활성화 후 대체 방식 |
---|---|
export const dynamic = ... | 'use dynamic' , 'use cache' 지시어로 대체 |
export const revalidate = 60 | cacheLife(60) 호출로 대체 |
export const fetchCache = ... | 별도 옵션 없음. 'use cache' 로 처리 |
export const dynamicParams = false | 더 이상 무의미. generateStaticParams() 는 계속 사용됨 |
실제 코드 예시
// Next.js 15, dynamicIO 기준 코드
export default async function Page({ params }: { params: { id: string } }) {
'use cache';
cacheLife('minutes'); // 60초 동안 캐시
const res = await fetch(`https://api.example.com/data/${params.id}`);
const data = await res.json();
return <div>{data.title}</div>;
}