문서
App Router 사용하기
generateStaticParams

generateStaticParams

generateStaticParams 함수는 동적 라우트 세그먼트와 함께 사용하여 요청에 따라 동적으로 처리되는 방식이 아닌 빌드 시 라우트를 정적으로 생성할 수 있습니다.

app/blog/[slug]/page.js
// [slug] 동적 세그먼트를 채울 `params` 목록을 반환합니다
export async function generateStaticParams() {
  const posts = await fetch("https://.../posts").then((res) => res.json());
 
  return posts.map((post) => ({
    slug: post.slug,
  }));
}
 
// 이 페이지의 여러 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
export default function Page({ params }) {
  const { slug } = params;
  // ...
}

알아두면 좋은 점

매개변수

options.params (선택사항)

라우트의 여러 동적 세그먼트가 generateStaticParams를 사용하는 경우, 하위 generateStaticParams 함수는 상위가 생성하는 각 params 세트에 대해 한 번씩 실행됩니다.

params 객체에는 상위 generateStaticParams에서 채워진 params가 포함되어 있으며, 이를 사용하여 하위 세그먼트에서 params를 생성할 수 있습니다.

반환값

generateStaticParams는 객체 배열을 반환해야 하며, 각 객체는 단일 라우트의 채워진 동적 세그먼트를 나타냅니다.

  • 객체의 각 속성은 라우트에 대해 채워질 동적 세그먼트입니다.
  • 속성의 이름은 세그먼트의 이름이고, 속성의 값은 해당 세그먼트가 채워져야 할 내용입니다.
예시 라우트generateStaticParams 반환 타입
/product/[id]{ id: string }[]
/products/[category]/[product]{ category: string, product: string }[]
/products/[...slug]{ slug: string[] }[]

단일 동적 세그먼트

app/product/[id]/page.tsx
export function generateStaticParams() {
  return [{ id: "1" }, { id: "2" }, { id: "3" }];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /product/1
// - /product/2
// - /product/3
export default function Page({ params }: { params: { id: string } }) {
  const { id } = params;
  // ...
}
app/product/[id]/page.js
export function generateStaticParams() {
  return [{ id: "1" }, { id: "2" }, { id: "3" }];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /product/1
// - /product/2
// - /product/3
export default function Page({ params }) {
  const { id } = params;
  // ...
}

여러 동적 세그먼트

app/products/[category]/[product]/page.tsx
export function generateStaticParams() {
  return [
    { category: "a", product: "1" },
    { category: "b", product: "2" },
    { category: "c", product: "3" },
  ];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /products/a/1
// - /products/b/2
// - /products/c/3
export default function Page({
  params,
}: {
  params: { category: string; product: string };
}) {
  const { category, product } = params;
  // ...
}
app/products/[category]/[product]/page.js
export function generateStaticParams() {
  return [
    { category: "a", product: "1" },
    { category: "b", product: "2" },
    { category: "c", product: "3" },
  ];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /products/a/1
// - /products/b/2
// - /products/c/3
export default function Page({ params }) {
  const { category, product } = params;
  // ...
}

전체 경로 처리 세그먼트 (Catch-all Segments)

app/product/[...slug]/page.tsx
export function generateStaticParams() {
  return [{ slug: ["a", "1"] }, { slug: ["b", "2"] }, { slug: ["c", "3"] }];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /product/a/1
// - /product/b/2
// - /product/c/3
export default function Page({ params }: { params: { slug: string[] } }) {
  const { slug } = params;
  // ...
}
app/product/[...slug]/page.js
export function generateStaticParams() {
  return [{ slug: ["a", "1"] }, { slug: ["b", "2"] }, { slug: ["c", "3"] }];
}
 
// 이 페이지의 세 가지 버전이 `generateStaticParams`가 반환한
// `params`를 사용하여 정적으로 생성됩니다
// - /product/a/1
// - /product/b/2
// - /product/c/3
export default function Page({ params }) {
  const { slug } = params;
  // ...
}

예시

정적 렌더링

빌드 시 모든 경로

빌드 시 모든 경로를 정적으로 렌더링하려면 generateStaticParams에 전체 경로 목록을 제공하세요:

app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch("https://.../posts").then((res) => res.json());
 
  return posts.map((post) => ({
    slug: post.slug,
  }));
}

빌드 시 일부 경로

빌드 시 일부 경로를 정적으로 렌더링하고 나머지는 런타임에 처음 방문할 때 렌더링하려면 부분적인 경로 목록을 반환하세요:

app/blog/[slug]/page.tsx
export async function generateStaticParams() {
  const posts = await fetch("https://.../posts").then((res) => res.json());
 
  // 빌드 시 처음 10개의 게시물을 렌더링합니다
  return posts.slice(0, 10).map((post) => ({
    slug: post.slug,
  }));
}

그런 다음 dynamicParams 세그먼트 구성 옵션을 사용하여 generateStaticParams로 생성되지 않은 동적 세그먼트를 방문할 때 어떤 일이 발생하는지 제어할 수 있습니다.

app/blog/[slug]/page.js
// 상위 10개 게시물 외의 모든 게시물은 404가 됩니다
export const dynamicParams = false;
 
export async function generateStaticParams() {
  const posts = await fetch("https://.../posts").then((res) => res.json());
  const topPosts = posts.slice(0, 10);
 
  return topPosts.map((post) => ({
    slug: post.slug,
  }));
}

런타임에 모든 경로

처음 방문할 때 모든 경로를 정적으로 렌더링하려면 빈 배열을 반환하거나 (빌드 시 경로가 렌더링되지 않음) export const dynamic = 'force-static'을 사용하세요:

app/blog/[slug]/page.js
export async function generateStaticParams() {
  return [];
}

알아두면 좋은 점: generateStaticParams에서는 항상 배열을 반환해야 합니다. 비어 있더라도 마찬가지입니다. 그렇지 않으면 라우트가 동적으로 렌더링됩니다.

app/changelog/[slug]/page.js
export const dynamic = "force-static";

지정되지 않은 경로에 대한 렌더링 비활성화

지정되지 않은 경로가 런타임에 정적으로 렌더링되는 것을 방지하려면 라우트 세그먼트에 export const dynamicParams = false 옵션을 추가하세요. 이 구성 옵션을 사용하면 generateStaticParams에서 제공한 경로만 제공되고, 지정되지 않은 라우트는 404가 되거나 (캐치올 라우트의 경우) 일치합니다.

라우트의 여러 동적 세그먼트

현재 레이아웃이나 페이지 위의 동적 세그먼트에 대한 매개변수를 생성할 수 있지만, 아래는 불가능합니다. 예를 들어, app/products/[category]/[product] 라우트의 경우:

  • app/products/[category]/[product]/page.js[category][product] 둘 다에 대한 매개변수를 생성할 수 있습니다.
  • app/products/[category]/layout.js[category]에 대한 매개변수 생성할 수 있습니다.

여러 동적 세그먼트가 있는 라우트에 대한 매개변수를 생성하는 두 가지 접근 방식이 있습니다:

아래에서 위로 매개변수 생성

하위 라우트 세그먼트에서 여러 동적 세그먼트를 생성합니다.

app/products/[category]/[product]/page.tsx
// [category]와 [product] 모두에 대한 세그먼트 생성
export async function generateStaticParams() {
  const products = await fetch("https://.../products").then((res) =>
    res.json()
  );
 
  return products.map((product) => ({
    category: product.category.slug,
    product: product.id,
  }));
}
 
export default function Page({
  params,
}: {
  params: { category: string; product: string };
}) {
  // ...
}
app/products/[category]/[product]/page.js
// [category]와 [product] 모두에 대한 세그먼트 생성
export async function generateStaticParams() {
  const products = await fetch("https://.../products").then((res) =>
    res.json()
  );
 
  return products.map((product) => ({
    category: product.category.slug,
    product: product.id,
  }));
}
 
export default function Page({ params }) {
  // ...
}

위에서 아래로 매개변수 생성

먼저 상위 세그먼트를 생성하고 그 결과를 사용하여 하위 세그먼트를 생성합니다.

app/products/[category]/layout.tsx
// [category]에 대한 세그먼트 생성
export async function generateStaticParams() {
  const products = await fetch("https://.../products").then((res) =>
    res.json()
  );
 
  return products.map((product) => ({
    category: product.category.slug,
  }));
}
 
export default function Layout({ params }: { params: { category: string } }) {
  // ...
}
app/products/[category]/layout.js
// [category]에 대한 세그먼트 생성
export async function generateStaticParams() {
  const products = await fetch("https://.../products").then((res) =>
    res.json()
  );
 
  return products.map((product) => ({
    category: product.category.slug,
  }));
}
 
export default function Layout({ params }) {
  // ...
}

하위 라우트 세그먼트의 generateStaticParams 함수는 상위 generateStaticParams가 생성하는 각 세그먼트에 대해 한 번씩 실행됩니다.

하위 generateStaticParams 함수는 상위 generateStaticParams 함수에서 반환된 params를 사용하여 동적으로 자체 세그먼트를 생성할 수 있습니다.

app/products/[category]/[product]/page.tsx
// 상위 세그먼트의 `generateStaticParams` 함수에서 전달된
// `params`를 사용하여 [product]에 대한 세그먼트 생성
export async function generateStaticParams({
  params: { category },
}: {
  params: { category: string };
}) {
  const products = await fetch(
    `https://.../products?category=${category}`
  ).then((res) => res.json());
 
  return products.map((product) => ({
    product: product.id,
  }));
}
 
export default function Page({
  params,
}: {
  params: { category: string; product: string };
}) {
  // ...
}
app/products/[category]/[product]/page.js
// 상위 세그먼트의 `generateStaticParams` 함수에서 전달된
// `params`를 사용하여 [product]에 대한 세그먼트 생성
export async function generateStaticParams({ params: { category } }) {
  const products = await fetch(
    `https://.../products?category=${category}`
  ).then((res) => res.json());
 
  return products.map((product) => ({
    product: product.id,
  }));
}
 
export default function Page({ params }) {
  // ...
}

알아두면 좋은 점: fetch 요청은 모든 generate 접두사가 붙은 함수, 레이아웃, 페이지 및 서버 컴포넌트에서 동일한 데이터에 대해 자동으로 메모이제이션됩니다. fetch를 사용할 수 없는 경우 React cache를 사용할 수 있습니다.

버전 기록

버전변경 사항
v13.0.0generateStaticParams 도입됨.