Catch all routes
Answered
In&Out posted this in #help-forum
In&OutOP
Hey folks, im trying to make a cms like site, where user can make own pages and stuff like that. Currently, they only have option to make home page, but i'd want them to also make pages like /PAGE/page1/page2/..., to make as much nested pages as they want, how would i go on about doing that? What do i also need for it, do i need db to store the paths or what, need full assistance please
Answered by Northeast Congo Lion
Sure! The exact approach will depend on your buildout, but here's essentially what I do.
I have a page that contains a slug field that the user can create (this is just a text field that I normalize to make sure it's a valid URL). There's also a relationship field that lets the user set a parent.
For example, if they create:
- 'About Us' page (slug: 'about-us', no parent) →
- 'Team' page (slug: 'team', parent: 'About Us') →
- 'Leadership' page (slug: 'leadership', parent: 'Team') →
To get that full path, you need to grab the current page's slug and then fetch the parents (ID and slug), walking up the chain until there are no more parents. Then you can build the full path by joining the slugs with
Within my
Some notes on this approach:
1. This approach is a bit complex but gives the end user complete flexibility to build whatever pages and routes they want.
2. Depending on your implementation, you'll need to account for things like:
- Preventing users from setting the page as its own parent
- Preventing circular references (Page A → Page B → Page A)
- Updating all child paths when a parent slug changes (e.g., if
- Normalizing slug fields to ensure valid URLs
3. It would be much simpler to just have the user type the desired full path manually (like
Overall, this approach gives users ultimate flexibility without having to remember how to format full paths correctly. They just set up the hierarchy naturally (parent-child relationships), and the system handles building the proper URLs automatically. The other benefit is that when a request comes in for a page, you don't have to do any complex tree walking to show the content - you've already pre-computed and stored the fullPath during content creation.
* Note that this is all without any context on what you're building exactly or your desired end use case. This is just how I've set it up with Payloadcms and Nextjs. 🙂
I have a page that contains a slug field that the user can create (this is just a text field that I normalize to make sure it's a valid URL). There's also a relationship field that lets the user set a parent.
For example, if they create:
- 'About Us' page (slug: 'about-us', no parent) →
/about-us
- 'Team' page (slug: 'team', parent: 'About Us') →
/about-us/team
- 'Leadership' page (slug: 'leadership', parent: 'Team') →
/about-us/team/leadership
To get that full path, you need to grab the current page's slug and then fetch the parents (ID and slug), walking up the chain until there are no more parents. Then you can build the full path by joining the slugs with
/
. I store this result in my database on the page row as a fullPath
field. This happens via a hook that Payload gives me. I run my generateFullPath function whenever the document gets saved. Within my
[[...slug]]
page.tsx file, I can then just fetch by the fullPath and build the slug following Next.js guide on optional catch-all segments.Some notes on this approach:
1. This approach is a bit complex but gives the end user complete flexibility to build whatever pages and routes they want.
2. Depending on your implementation, you'll need to account for things like:
- Preventing users from setting the page as its own parent
- Preventing circular references (Page A → Page B → Page A)
- Updating all child paths when a parent slug changes (e.g., if
about-us
becomes about
)- Normalizing slug fields to ensure valid URLs
3. It would be much simpler to just have the user type the desired full path manually (like
/about-us/team
), however that comes with the tradeoff of needing to manually update each page if a parent slug ever changes.Overall, this approach gives users ultimate flexibility without having to remember how to format full paths correctly. They just set up the hierarchy naturally (parent-child relationships), and the system handles building the proper URLs automatically. The other benefit is that when a request comes in for a page, you don't have to do any complex tree walking to show the content - you've already pre-computed and stored the fullPath during content creation.
* Note that this is all without any context on what you're building exactly or your desired end use case. This is just how I've set it up with Payloadcms and Nextjs. 🙂
6 Replies
In&OutOP
Please tag me if you answer
Northeast Congo Lion
@In&Out On the front end you can create a dynamic route segment (blog/[slug]/page.tsx). Most likely you'd want an optional catch all segment using [[...slug]]/page.tsx. This would allow you to use a single page and layout for any route and nested route that matches the segment.
https://nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes#convention
I do this now for a site with Payload CMS, which let's the client create pages/nested pages using a page builder.
As for the user experience on creating pages, that's all up to you. You'll most likely need a db or something to store the paths and content for the pages. One thing I'd recommend though is computing the full path and storing that directly (vs just the parent/child relationships). This will make route resolution much quicker and avoids having to use recursive queries to build the full path.
https://nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes#convention
I do this now for a site with Payload CMS, which let's the client create pages/nested pages using a page builder.
As for the user experience on creating pages, that's all up to you. You'll most likely need a db or something to store the paths and content for the pages. One thing I'd recommend though is computing the full path and storing that directly (vs just the parent/child relationships). This will make route resolution much quicker and avoids having to use recursive queries to build the full path.
@Northeast Congo Lion <@959521575672086568> On the front end you can create a dynamic route segment (blog/[slug]/page.tsx). Most likely you'd want an optional catch all segment using [[...slug]]/page.tsx. This would allow you to use a single page and layout for any route and nested route that matches the segment.
https://nextjs.org/docs/app/api-reference/file-conventions/dynamic-routes#convention
I do this now for a site with Payload CMS, which let's the client create pages/nested pages using a page builder.
As for the user experience on creating pages, that's all up to you. You'll most likely need a db or something to store the paths and content for the pages. One thing I'd recommend though is computing the full path and storing that directly (vs just the parent/child relationships). This will make route resolution much quicker and avoids having to use recursive queries to build the full path.
In&OutOP
"computing the full path and storing that directly", can you elaborate on this please
Northeast Congo Lion
Sure! The exact approach will depend on your buildout, but here's essentially what I do.
I have a page that contains a slug field that the user can create (this is just a text field that I normalize to make sure it's a valid URL). There's also a relationship field that lets the user set a parent.
For example, if they create:
- 'About Us' page (slug: 'about-us', no parent) →
- 'Team' page (slug: 'team', parent: 'About Us') →
- 'Leadership' page (slug: 'leadership', parent: 'Team') →
To get that full path, you need to grab the current page's slug and then fetch the parents (ID and slug), walking up the chain until there are no more parents. Then you can build the full path by joining the slugs with
Within my
Some notes on this approach:
1. This approach is a bit complex but gives the end user complete flexibility to build whatever pages and routes they want.
2. Depending on your implementation, you'll need to account for things like:
- Preventing users from setting the page as its own parent
- Preventing circular references (Page A → Page B → Page A)
- Updating all child paths when a parent slug changes (e.g., if
- Normalizing slug fields to ensure valid URLs
3. It would be much simpler to just have the user type the desired full path manually (like
Overall, this approach gives users ultimate flexibility without having to remember how to format full paths correctly. They just set up the hierarchy naturally (parent-child relationships), and the system handles building the proper URLs automatically. The other benefit is that when a request comes in for a page, you don't have to do any complex tree walking to show the content - you've already pre-computed and stored the fullPath during content creation.
* Note that this is all without any context on what you're building exactly or your desired end use case. This is just how I've set it up with Payloadcms and Nextjs. 🙂
I have a page that contains a slug field that the user can create (this is just a text field that I normalize to make sure it's a valid URL). There's also a relationship field that lets the user set a parent.
For example, if they create:
- 'About Us' page (slug: 'about-us', no parent) →
/about-us
- 'Team' page (slug: 'team', parent: 'About Us') →
/about-us/team
- 'Leadership' page (slug: 'leadership', parent: 'Team') →
/about-us/team/leadership
To get that full path, you need to grab the current page's slug and then fetch the parents (ID and slug), walking up the chain until there are no more parents. Then you can build the full path by joining the slugs with
/
. I store this result in my database on the page row as a fullPath
field. This happens via a hook that Payload gives me. I run my generateFullPath function whenever the document gets saved. Within my
[[...slug]]
page.tsx file, I can then just fetch by the fullPath and build the slug following Next.js guide on optional catch-all segments.Some notes on this approach:
1. This approach is a bit complex but gives the end user complete flexibility to build whatever pages and routes they want.
2. Depending on your implementation, you'll need to account for things like:
- Preventing users from setting the page as its own parent
- Preventing circular references (Page A → Page B → Page A)
- Updating all child paths when a parent slug changes (e.g., if
about-us
becomes about
)- Normalizing slug fields to ensure valid URLs
3. It would be much simpler to just have the user type the desired full path manually (like
/about-us/team
), however that comes with the tradeoff of needing to manually update each page if a parent slug ever changes.Overall, this approach gives users ultimate flexibility without having to remember how to format full paths correctly. They just set up the hierarchy naturally (parent-child relationships), and the system handles building the proper URLs automatically. The other benefit is that when a request comes in for a page, you don't have to do any complex tree walking to show the content - you've already pre-computed and stored the fullPath during content creation.
* Note that this is all without any context on what you're building exactly or your desired end use case. This is just how I've set it up with Payloadcms and Nextjs. 🙂
Answer
@Northeast Congo Lion Sure! The exact approach will depend on your buildout, but here's essentially what I do.
I have a page that contains a slug field that the user can create (this is just a text field that I normalize to make sure it's a valid URL). There's also a relationship field that lets the user set a parent.
For example, if they create:
- 'About Us' page (slug: 'about-us', no parent) → `/about-us`
- 'Team' page (slug: 'team', parent: 'About Us') → `/about-us/team`
- 'Leadership' page (slug: 'leadership', parent: 'Team') → `/about-us/team/leadership`
To get that full path, you need to grab the current page's slug and then fetch the parents (ID and slug), walking up the chain until there are no more parents. Then you can build the full path by joining the slugs with `/`. I store this result in my database on the page row as a `fullPath` field. This happens via a hook that Payload gives me. I run my generateFullPath function whenever the document gets saved.
Within my `[[...slug]]` page.tsx file, I can then just fetch by the fullPath and build the slug following Next.js guide on optional catch-all segments.
**Some notes on this approach:**
1. This approach is a bit complex but gives the end user complete flexibility to build whatever pages and routes they want.
2. Depending on your implementation, you'll need to account for things like:
- Preventing users from setting the page as its own parent
- Preventing circular references (Page A → Page B → Page A)
- Updating all child paths when a parent slug changes (e.g., if `about-us` becomes `about`)
- Normalizing slug fields to ensure valid URLs
3. It would be much simpler to just have the user type the desired full path manually (like `/about-us/team`), however that comes with the tradeoff of needing to manually update each page if a parent slug ever changes.
Overall, this approach gives users ultimate flexibility without having to remember how to format full paths correctly. They just set up the hierarchy naturally (parent-child relationships), and the system handles building the proper URLs automatically. The other benefit is that when a request comes in for a page, you don't have to do any complex tree walking to show the content - you've already pre-computed and stored the fullPath during content creation.
* Note that this is all without any context on what you're building exactly or your desired end use case. This is just how I've set it up with Payloadcms and Nextjs. 🙂
In&OutOP
Dang wow, okay that's everything i need, thank you
Northeast Congo Lion
Of course happy to help!