This document describes how the page hierarchy is structured in Strapi - how pages are organized, how their URLs are generated and how to manage changes in the hierarchy.
The visitable pages are organized in a hierarchy using the parent and (optionally) children relation fields. Each page can have a parent page, and it can also have multiple child pages. It's important to maintain correct relations between pages to ensure proper hierarchy, breadcrumbs and navigation.
Following collections are used to store pages. That means that every following page is visitable from frontend and has its own URL.
This collection is used to store general pages of the website. There is one root/index/home page that has no parent, its slug is set to / (see ROOT_PAGE_PATH constant). All other pages from this collection are children of this root page. The / value can't be changed from admin panel. The slug doesn't need to be unique and can be same if the parent is different (needs to be maintain manually).
The fullpath of every page is created by chaining the slugs of all its parents. It always starts with / prefix. The fullPath is automatically generated by the system (see below).
Every page from collections above has required slug field, which is used to identify the page in the URL. Uniqueness of the slug depends on the collection (see above). The slug must be lowercase and can contain only letters, numbers and hyphens so it follows [a-z0-9/-]+$ pattern. Slug never starts or ends with a slash and must be set manually in the admin panel.
The fullPath field is automatically generated and contains the full path of the page, including all parent slugs. It is main identifier used to render the page from the URL (frontend finds pages using fullPath filter).
The fullPath is generated from the slug and the parent relation field. Automatic generation of fullPath can be disabled on the code level (by setting PAGES_HIERARCHY_ENABLED to false in the Strapi codebase).
Because the fullPath is generated automatically, it should never be edited manually. If you need to change the fullPath, change the slug or the parent relation field instead. Change in fullPath means, that the page has different URL address and old URL should redirect to the new URL. This is done automatically be creating redirect (api::redirect.redirect) records. These two operations are always linked together and should never be done separately. Creating redirects makes sense only when new website is already live! During development, the fullPath can be changed (recalculated) without creating redirects.
When the fullPath of a page is changed (because its slug or parent was changed), a redirect from the old fullPath to the new fullPath is automatically created. This is done using internal jobs (see below) and requires manual triggering of the jobs in the admin panel. Any other change (e.g. in children relation) doesn't affect this process.
-
Every time the published page changes the
slugorparentrelation field a new internal job (api::internal-job.internal-job) is created to regenerate thefullPathfield. It hastypeset toRECALCULATE_FULLPATHandstatusset toPENDING(see "Internal Jobs" content type in admin panel). -
The
fullPathis not updated immediately, but after the job is processed. This is done to avoid performance issues and cascading updates of thefullPathfield for all child pages within lifecycle hooks. To trigger the recalculation of thefullPathof all pending jobs, click the "Recalculate all fullpaths" button in the admin panel. This will update thefullPathfield for all pending pages and their children. All pages will be published during this update, so after triggering, related pages will be live with newfullPathvalues. The recalculation is done in the background, so it may take some time depending on the number of pages and their hierarchy. -
During the recalculation, the script create
CREATE_REDIRECTinternal jobs for all pages that have changedfullPathand save them in the "Internal Jobs" content type. To trigger them, click the "Create all redirects" button in the admin panel. This will create redirects (api::redirect.redirect) for all included jobs and save them in the "Redirect" content type. Redirects are locale-aware and theiroldPathandnewPathfields include locale prefix.
We want to change the slug of a page from page-a to page-b in en locale. This page has a child page with slug page-child.
-
Update the
slugfield of the page topage-b. -
Go to "Internal Jobs" content type and click the "Recalculate all fullpaths" button. Wait until the job is processed.
-
Go to "Internal Jobs" content type and click the "Create all redirects" button. Wait until the job is processed.
-
Verify that the page has new
fullPathand its child page (page-child) has updatedfullPathas well. -
Verify that 2 redirects are created in the "Redirect" collection for the page and its children. Their
sourceanddestinationURLs should be correct and also include locale prefix:-
/en/page-a->/en/page-b -
/en/page-a/page-child->/en/page-b/page-child
-
-
Always maintain correct
parentrelations between pages to ensure proper hierarchy and URL structure. -
Always trigger these jobs in sequence: first "Recalculate all fullpaths" and after it's done, "Create all redirects". This way you ensure that all pages have correct
fullPathand all necessary redirects are created. -
Always do these operations during low traffic times, as they may affect performance and user experience.
-
Do one change at a time (e.g. change slug of one page, trigger jobs, verify results, then change slug of another page, etc.). This way you can easily track changes and avoid mistakes.
-
Until the
RECALCULATE_FULLPATHjob is processed, thefullPathfield of the page is not updated and still contains the old value. This means that the page is still accessible from the old URL until the job is processed. -
Algorithm deletes jobs once they are processed, so you can't re-trigger them. If you need to re-trigger the job, you must change the
slugorparentfield again to create a new job. -
Once the
CREATE_REDIRECTjob is processed, any other change will produce a newRECALCULATE_FULLPATHjob and then after submitting theCREATE_REDIRECTjob, a new redirect will be created with the latest values. -
Strapi handles every locale separately - page in
enlocale can have differentslugor even differentparentrelation. That means that changing theslugin one locale creates jobs only for that locale. If you want to change theslugin multiple locales, you must manually do same change for every required locale (it isn't a bug).- Based on this, the redirects are also created separately for each touched locale and the locale is embedded into
sourceanddestinationURLs.
- Based on this, the redirects are also created separately for each touched locale and the locale is embedded into
-
Unrelevant jobs are automatically deleted:
-
slug
achanged tob, then tocbefore processing - only job forcis kept. The redirect fromatocis created. -
slug
achanged tob, then back toabefore processing - no job is kept, no redirect is created.
-
-
Jobs can be manually deleted from admin panel if they were created by mistake.
-
During development or before going live, we should only recalculate
fullPathwithout creating redirects. In this case we should manually deleteCREATE_REDIRECTjobs from admin panel. -
Try to avoid having many pending jobs at the same time. Process them as soon as possible to avoid confusion.
-
You can't change
/slug from admin panel. The change requires update on the code level.
- Page Builder — Page Builder specific documentation