Optional Catch-all

[[...slug]]

Double brackets make the catch-all optional: it also matches the folder itself. Perfect for a shop with filter paths: app/shop/[[...filters]]/page.tsx.

URLparams
/shop{ } (filters is undefined)
/shop/mobiles{ filters: ['mobiles'] }
/shop/mobiles/samsung/under-20000{ filters: ['mobiles', 'samsung', 'under-20000'] }
export default async function ShopPage({
  params,
}: {
  params: Promise<{ filters?: string[] }>;
}) {
  const { filters = [] } = await params;
  const [category, brand] = filters;
  return (
    <h1>
      {category ?? 'All products'} {brand ? '— ' + brand : ''}
    </h1>
  );
}

Choosing a Pattern

PatternMatches /shopMatches /shop/aMatches /shop/a/b
[slug]NoYesNo
[...slug]NoYesYes
[[...slug]]YesYesYes