Topic 33 of 47
[...slug]
Overview
Catch-all routes match a dynamic segment and all subsequent segments in a URL. They are created by adding an ellipsis `...` inside the brackets. This is useful for complex nested data structures like documentation or file explorers.
Syntax
tsx
// Folder structure: app/docs/[...slug]/page.tsx
// Matches:
// /docs/intro -> params.slug is ["intro"]
// /docs/getting-started/v1 -> params.slug is ["getting-started", "v1"]
// /docs/api/auth/login -> params.slug is ["api", "auth", "login"]
export default function DocsPage({ params }: { params: { slug: string[] } }) {
// Join the array segments into a path string
const path = params.slug.join('/');
return <h1>Viewing documentation for: {path}</h1>;
}Common Pitfalls
- A standard catch-all route `[...slug]` does NOT match the root path (e.g., `/docs` will 404). Use an optional catch-all `[[...slug]]` if you want it to match the root.
Real-World Example
Optional Catch-All Routes ([[...slug]]):
example
tsx
// Folder structure: app/shop/[[...slug]]/page.tsx
// Notice the DOUBLE brackets. This makes the route OPTIONAL.
// Matches:
// /shop -> params.slug is undefined
// /shop/clothes -> params.slug is ["clothes"]
// /shop/clothes/tops -> params.slug is ["clothes", "tops"]
export default function Shop({ params }: { params: { slug?: string[] } }) {
if (!params.slug) {
return <h1>All Products (Root Category)</h1>;
}
const categoryPath = params.slug.join(' > ');
return <h1>Category: {categoryPath}</h1>;
}