--- title: "Nested Docs Plugin" aliases: [nested-docs, plugin-nested-docs, parent-child-pages] tags: [payloadcms, plugin, hierarchy, breadcrumbs, pages] sources: [raw/plugins__nested-docs.md] created: 2026-05-15 updated: 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 ```bash pnpm add @payloadcms/plugin-nested-docs ``` ## Basic Setup ```ts 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`/`breadcrumbs` fields **must** be at the top level — not inside a `group`, `array`, or `blocks`. ## Field Overrides Use `createParentField` / `createBreadcrumbsField` to extend the built-in fields: ```ts 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 `name` of either field, set `parentFieldSlug` / `breadcrumbsFieldSlug` in plugin options. ## Localization When `localization` is enabled in Payload Config, the `breadcrumbs` field is automatically localized. See [[wiki/payloadcms/localization|Localization]]. ## TypeScript ```ts import type { NestedDocsPluginConfig, GenerateURL, GenerateLabel, } from '@payloadcms/plugin-nested-docs/types' ``` ## Key Takeaways - Plugin injects `parent` + `breadcrumbs` fields; updates cascade recursively down the tree - `generateURL` builds full paths like `/about/company/our-team` from breadcrumb docs array - Custom fields are supported — set `parentFieldSlug`/`breadcrumbsFieldSlug` and place them **at top-level only** - Use `createParentField`/`createBreadcrumbsField` when you need sidebar placement or label overrides - Localization is automatic when Payload's `localization` config is set - Official Website Template in the Payload repo uses this plugin as a reference ## Related - [[wiki/payloadcms/hierarchy|Hierarchy — Tree Structure]] — Payload's built-in hierarchy feature (virtual slug/title paths, different approach) - [[wiki/payloadcms/plugins|Official Plugins]] — all 10 official plugins overview - [[wiki/payloadcms/localization|Localization — Content Internationalization]] — locale config used by breadcrumbs - [[wiki/payloadcms/fields-relationship|Relationship Field]] — underlying field type used for `parent` ## Sources - `raw/plugins__nested-docs.md` - https://payloadcms.com/docs/plugins/nested-docs