본문으로 건너뛰기

동적 페이지를 미리 만드는 이유

상품 상세 페이지나 블로그처럼 URL의 일부가 데이터에 따라 달라지는 페이지가 있습니다.

/products/1
/products/2
/products/3

Next.js에서는 [id]를 사용해 하나의 Page에서 이런 URL을 모두 처리할 수 있습니다.

app/
└─ products/
└─ [id]/
└─ page.tsx

그런데 여기서 한 가지 문제가 생깁니다.

상품 페이지를 사용자가 요청할 때마다 서버에서 새로 만들어야 할까요?

이미 어떤 상품이 존재하는지 알고 있고, 그 페이지를 미리 만들 수 있다면 굳이 사용자가 접속할 때까지 기다릴 필요가 없습니다.

이때 사용하는 것이 generateStaticParams입니다.


사용자가 요청하기 전에 페이지를 미리 만듭니다​

예를 들어 상품이 다음과 같이 있다고 해보겠습니다.

상품
1. iPhone
2. MacBook
3. AirPods

generateStaticParams에서 미리 만들 상품을 알려줄 수 있습니다.

export async function generateStaticParams() {
return [
{ id: '1' },
{ id: '2' },
{ id: '3' },
]
}

Next.js는 빌드할 때 generateStaticParams를 실행하고, 반환된 id를 이용해 각 페이지를 미리 렌더링합니다. (nextjs.org)

빌드

generateStaticParams()
↓
id = 1, 2, 3
↓
각 id로 Page 렌더링
↓
상품 페이지 미리 준비

그래서 사용자가 /products/1에 접속했을 때 처음부터 페이지를 만드는 것이 아니라, 빌드 과정에서 준비해 둔 결과를 사용할 수 있습니다.


그렇다면 페이지 내용은 어떻게 달라질까요?​

상품마다 페이지 내용은 당연히 다릅니다.

/products/1 → iPhone
/products/2 → MacBook
/products/3 → AirPods

generateStaticParams는 상품 정보를 만드는 함수가 아닙니다.

어떤 id의 페이지를 미리 만들지 알려주는 역할만 합니다.

실제 데이터는 page.tsx에서 가져옵니다.

export async function generateStaticParams() {
return [
{ id: '1' },
{ id: '2' },
{ id: '3' },
]
}

export default async function Page({ params }) {
const { id } = await params

const product = await getProduct(id)

return <h1>{product.name}</h1>
}

개념적으로 보면:

generateStaticParams()
↓
"1, 2, 3 페이지를 만들어줘"
↓
┌──────────────┐
│ page.tsx │
└──────────────┘
↓ ↓ ↓
id=1 id=2 id=3
↓ ↓ ↓
상품1 상품2 상품3

즉,

generateStaticParams
→ 어떤 페이지를 미리 만들까?

page.tsx
→ 그 페이지에 무엇을 보여줄까?

로 역할이 나뉩니다.


왜 미리 만들어 두는 것이 좋을까요?​

사용자가 페이지를 요청할 때마다 서버에서 처음부터 렌더링한다고 생각해봅시다.

사용자 요청
↓
서버에서 데이터 조회
↓
Server Component 실행
↓
페이지 렌더링
↓
사용자에게 전달

페이지를 만드는 데 시간이 걸린다면 사용자는 그만큼 기다려야 합니다.

반면 빌드 시점에 미리 만들어 두면:

빌드
↓
페이지 미리 렌더링
↓
사용자 요청
↓
준비된 페이지 사용

이렇게 사용자가 페이지를 요청한 뒤 해야 할 작업을 줄일 수 있습니다.

즉 generateStaticParams를 사용하는 가장 큰 이유는

미리 알 수 있는 Dynamic Route를 사용자가 방문하기 전에 prerender하기 위해서입니다.


모든 동적 페이지를 미리 만들 필요는 없습니다​

그렇다고 모든 상품을 빌드할 때 전부 만드는 것이 항상 좋은 것은 아닙니다.

상품이 100개라면 괜찮을 수 있지만,

상품 1,000,000개

라면 모든 상품 페이지를 빌드할 때 만드는 것은 부담이 될 수 있습니다.

그래서 generateStaticParams에는 미리 만들고 싶은 params만 반환할 수 있습니다.

export async function generateStaticParams() {
return [
{ id: '1' },
{ id: '2' },
{ id: '3' },
]
}

예를 들어 조회수가 높은 상품이나 자주 방문하는 페이지처럼 미리 만들어 둘 가치가 있는 페이지를 선택할 수 있습니다.


Dynamic Route와 함께 이해해야 합니다​

여기서 중요한 점은 generateStaticParams가 Dynamic Route를 없애는 것이 아니라는 것입니다.

app/
└─ products/
└─ [id]/
└─ page.tsx

여전히 /products/[id]라는 Dynamic Route입니다.

다만 그중 일부 params를:

/products/1
/products/2
/products/3

빌드 시점에 미리 렌더링하는 것입니다.

따라서:

Dynamic Route
→ 여러 URL을 하나의 Page로 처리

generateStaticParams
→ 그중 어떤 URL을 미리 만들어 둘지 결정

이라고 이해하면 됩니다.


전체 흐름​

결국 generateStaticParams는 다음과 같은 흐름을 만듭니다.

Dynamic Route

/products/[id]
↓
generateStaticParams()
↓
{id: "1"}
{id: "2"}
{id: "3"}
↓
빌드 시 Page 렌더링
↓
미리 준비된 페이지
↓
사용자가 요청
↓
빠르게 페이지 제공

정리하면 generateStaticParams는 동적인 URL을 사용하는 페이지라도, 이미 알고 있는 params에 대해서는 사용자가 방문하기 전에 미리 만들어 두기 위한 기능입니다.

동적인 URL
↓
미리 알 수 있는 params
↓
generateStaticParams
↓
빌드 시 prerender
↓
사용자 요청 시 기다릴 작업 감소

따라서 generateStaticParams의 핵심은 "동적 페이지를 어떻게 만드는가"가 아니라 "동적 페이지 중 무엇을 미리 만들어 둘 것인가"에 있습니다.