본문 바로가기
C.W.K.
Stream
Lesson 05 of 10 · published

동적 라우트의 세 가지 모양

~22 min · dynamic segment, catch-all, optional

Level 0호기심
0 XP0/68 lessons0/11 achievements
0/120 XP to next level120 XP to go0% complete

대괄호가 주소의 변수를 잡아

파일 시스템 라우팅에서도 고정할 수 없는 주소 조각이 있어. 폴더 이름을 대괄호로 감싸면 실제 URL 값을 params로 받을 수 있어. 한 조각, 한 조각 이상, 아무 조각도 없을 수 있는 경우에 따라 표기가 달라져.

폴더 형태주소 예params 모양
[slug]/blog/hello{ slug: 'hello' }
[...slug]/docs/a/b/c{ slug: ['a','b','c'] }
[[...slug]]/docs 또는 /docs/a/b{ slug: undefined } 또는 { slug: ['a','b'] }

여러 동적 구간도 한 객체로 모여

app/shop/[category]/[item]/page.tsx처럼 한 경로에 변수가 여러 개 있어도 돼. 페이지가 받는 params에는 categoryitem이 한 객체로 합쳐져 들어와. Next.js 15 이상에서는 그 객체를 Promise에서 꺼낸다는 점도 잊지 마.

미리 만들지 않은 값의 운명을 정해

generateStaticParams가 빌드 때 일부 값만 만들었더라도, 기본 설정에서는 목록에 없던 값이 요청되면 그 자리에서 렌더링해. 알려지지 않은 slug를 반드시 404로 막고 싶다면 export const dynamicParams = false를 선언해. 정적 목록을 만들었다는 사실만으로 허용 목록이 되는 건 아니야.

동적 구간을 만들 때 허용 가능한 값의 집합과 미리 만들 값의 집합을 따로 적어. 인기 글 100개만 빌드하되 나머지 글도 첫 요청에 만들 수 있고, 문서 버전처럼 정해진 값만 허용한다면 dynamicParams = false가 맞아. 두 결정을 하나로 섞으면 예상 밖 404나 무한한 페이지 생성이 생겨.

catch-all이 폴더 수를 줄여 준다고 모든 계층에 맞는 건 아니야. 한 배열로 받은 경로를 다시 해석하는 코드가 제품의 URL 규칙을 숨길 수 있어. 계층마다 의미와 화면이 다르면 명시적 동적 구간을 나누는 편이 타입·메타데이터·오류 경계를 더 분명하게 해. 단일·catch-all·선택 catch-all 경로에 빈 값과 여러 조각을 보내 params 모양을 기록해. generateStaticParams 목록 안팎을 각각 요청하고 dynamicParams를 바꿨을 때 첫 요청 렌더링과 404가 어떻게 달라지는지 production build에서 확인해.

Code

선택 catch-all 경로·tsx
// app/docs/[[...slug]]/page.tsx
type Props = { params: Promise<{ slug?: string[] }> };

export default async function DocsPage({ params }: Props) {
  const { slug } = await params;
  if (!slug) return <DocsIndex />;

  const path = slug.join('/'); // 'getting-started/install'
  const doc = await getDoc(path);
  if (!doc) notFound();
  return <DocContent doc={doc} />;
}
두 동적 구간·tsx
// app/[locale]/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';

type Props = { params: Promise<{ locale: string; slug: string }> };

export default async function Page({ params }: Props) {
  const { locale, slug } = await params;
  const post = await getPost(locale, slug);
  if (!post) notFound();
  return <Article post={post} />;
}
알 수 없는 slug를 404로 끝내기·tsx
// app/blog/[slug]/page.tsx
export const dynamicParams = false;

export async function generateStaticParams() {
  const slugs = await getAllPostSlugs();
  return slugs.map(slug => ({ slug }));
}

External links

Exercise

app/docs/[[...slug]]/page.tsx/docs/docs/a/b/c를 모두 처리해. 알려진 slug 세 개를 미리 만들고 dynamicParams = false가 나머지를 404로 보내는지 확인해.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.