Next.js Discord

Discord Forum

Top level catch-all route alongside a dynamic route? Using Next14 with app router

Unanswered
Russian Blue posted this in #help-forum
Open in Discord
Russian BlueOP
What is the correct way to have a top level catch-all route (i.e. /app/[...slugs]/page.tsx) alongside a dynamic route (i.e. /app/[slug]/page.tsx)? I've managed to get it working by trying to retrieve the 'slug' from our CMS in the dynamic route (/app/[slug]), if that is not found we then call the Page export from the catch-all route passing in params something like: <Page params={{ slugs: [params.slug] }} /> . This works but feels a bit wrong, especially in my use case I have this at 3 levels so the catch-all (/app/[...slugs]) also tries to fetch data from the CMS if it is not found it then passes this onto another route (in my case /app/product/[slug]).

I've asked this same question in the NextJS subreddit with some more detail: https://www.reddit.com/r/nextjs/comments/1dj4kzt/

1 Reply

@Russian Blue What is the correct way to have a top level catch-all route (i.e. /app/[...slugs]/page.tsx) alongside a dynamic route (i.e. /app/[slug]/page.tsx)? I've managed to get it working by trying to retrieve the 'slug' from our CMS in the dynamic route (/app/[slug]), if that is not found we then call the Page export from the catch-all route passing in params something like: `<Page params={{ slugs: [params.slug] }} />` . This works but feels a bit wrong, especially in my use case I have this at 3 levels so the catch-all (/app/[...slugs]) also tries to fetch data from the CMS if it is not found it then passes this onto another route (in my case /app/product/[slug]). I've asked this same question in the NextJS subreddit with some more detail: https://www.reddit.com/r/nextjs/comments/1dj4kzt/
i dont think nextjs supports two dynamic segments at the same level. the reason is that for a request /something, nextjs doesn't know whether to route it to the [slug] or the [...slug]. afaik the precedence of predetermined segments over dynamic segments doesn't extend to different segment types.

you probably have to unify them all into one single app/[...slug]/page.tsx file, where you can do something like
if (slug.length === 1)
  return <Article slug={slug[0]} />

if (slug.length >= 3) notFound();

const [category, subCatOrProduct] = slug;
// do something to determine whether it is a subcategory or a product
// then return the correct component.


for static generation, you can do something like
// generateStaticParams()
const allArticles = await getAllArticlesSlugs();
const allCategories = await getAllCategoriesSlugs();
const allCatAndSubCat = await Promise.all(
  allCategories.map(
    async cat => [cat, await getSubCategories(cat)]
  )
);
return [
  ...allArticles.map(a => ({ slug: [a.slug] })),
  ...allCategories.map(cat => ({ slug: [cat.slug] })),
  ...allCatAndSubCat.map(cs => ({ slug: cs })),
];

with dynamicParams = true (or you can go one step further and add the product URLs and whatnot inside the returned array too.