4 KiB
| title | aliases | tags | sources | created | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Nested Docs Plugin |
|
|
|
2026-05-15 | 2026-05-15 |
Overview
@payloadcms/plugin-nested-docs adds parent/child hierarchy to any collection. It injects two fields — parent (relationship) and breadcrumbs (array) — and recursively updates all descendants whenever a parent changes.
Common use case: hierarchical page tree (/about/company/our-team).
Install
pnpm add @payloadcms/plugin-nested-docs
Basic Setup
import { nestedDocsPlugin } from '@payloadcms/plugin-nested-docs'
buildConfig({
plugins: [
nestedDocsPlugin({
collections: ['pages'],
generateLabel: (_, doc) => String(doc.title),
generateURL: (docs) =>
docs.reduce((url, doc) => `${url}/${String(doc.slug)}`, ''),
}),
],
})
Auto-Injected Fields
parent
- Relationship field pointing to another doc in the same collection
- Editor picks the direct parent; plugin builds the full ancestry chain
breadcrumbs
Array of ancestor objects, each with:
| Field | Default | Override via |
|---|---|---|
label |
admin.useAsTitle or doc ID |
generateLabel option |
url |
undefined |
generateURL option |
Breadcrumbs cascade automatically — if a grandparent slug changes, every descendant's breadcrumbs update.
Plugin Options
| Option | Type | Description |
|---|---|---|
collections |
string[] |
Collection slugs to enable |
generateLabel |
(docs, doc, collection, req) => string |
Dynamic breadcrumb label |
generateURL |
(docs, doc, collection, req) => string |
Dynamic breadcrumb URL |
parentFieldSlug |
string |
Use your own parent field (must be top-level) |
breadcrumbsFieldSlug |
string |
Use your own breadcrumbs field (must be top-level) |
Gotcha: custom
parent/breadcrumbsfields must be at the top level — not inside agroup,array, orblocks.
Field Overrides
Use createParentField / createBreadcrumbsField to extend the built-in fields:
import { createParentField, createBreadcrumbsField } from '@payloadcms/plugin-nested-docs'
fields: [
createParentField('pages', {
admin: { position: 'sidebar' },
// keep self-reference guard: filterOptions: ({ id }) => ({ id: { not_equals: id } })
}),
createBreadcrumbsField('pages', { label: 'Page Breadcrumbs' }),
]
If you override the
nameof either field, setparentFieldSlug/breadcrumbsFieldSlugin plugin options.
Localization
When localization is enabled in Payload Config, the breadcrumbs field is automatically localized. See wiki/payloadcms/localization.
TypeScript
import type {
NestedDocsPluginConfig,
GenerateURL,
GenerateLabel,
} from '@payloadcms/plugin-nested-docs/types'
Key Takeaways
- Plugin injects
parent+breadcrumbsfields; updates cascade recursively down the tree generateURLbuilds full paths like/about/company/our-teamfrom breadcrumb docs array- Custom fields are supported — set
parentFieldSlug/breadcrumbsFieldSlugand place them at top-level only - Use
createParentField/createBreadcrumbsFieldwhen you need sidebar placement or label overrides - Localization is automatic when Payload's
localizationconfig is set - Official Website Template in the Payload repo uses this plugin as a reference
Related
- wiki/payloadcms/hierarchy — Payload's built-in hierarchy feature (virtual slug/title paths, different approach)
- wiki/payloadcms/plugins — all 10 official plugins overview
- wiki/payloadcms/localization — locale config used by breadcrumbs
- wiki/payloadcms/fields-relationship — underlying field type used for
parent
Sources
raw/plugins__nested-docs.md- https://payloadcms.com/docs/plugins/nested-docs