Hierarchy
The Hierarchy feature provides automatic tree structure management for any Payload collection. When enabled, it maintains parent-child relationships, generates breadcrumb paths, and enables efficient descendant queries.
Use it for: Nested pages, categories, organizational structures, folder systems, or any hierarchical data.
Quick Start
Enable hierarchy on any collection by adding the hierarchy property:
This automatically:
- Creates a
parentrelationship field (if it doesn't exist) - Adds virtual
_h_slugPathand_h_titlePathfields (computed on-demand) - Sets up hooks to validate circular references and clean up tree on deletion
- Computes breadcrumb paths based on
admin.useAsTitlewhen requested
Auto-Generated Fields
When hierarchy is enabled, virtual path fields are automatically added to your collection. These fields are computed on-demand when requested and are not stored in the database.
_h_slugPath
Type: String or Localized Object (virtual field) Purpose: Slugified breadcrumb path for URLs and search Stored: No - computed on-demand from ancestor tree Read-only: Yes Requires: Opt-in (see Requesting Path Computation)
Use for URLs:
_h_titlePath
Type: String or Localized Object (virtual field) Purpose: Human-readable breadcrumb path for display Stored: No - computed on-demand from ancestor tree Read-only: Yes Requires: Opt-in (see Requesting Path Computation)
Use for breadcrumbs:
Requesting Path Computation
Path fields (_h_slugPath and _h_titlePath) are virtual fields that must be explicitly requested. This opt-in design prevents unnecessary database queries when paths aren't needed (e.g., when loading documents through relationships).
Method 1: Context Flag
Pass computeHierarchyPaths: true in the context:
Method 2: Query Parameter
For REST API requests, add the computeHierarchyPaths query parameter:
Method 3: Field Selection
Paths are automatically computed when you explicitly select them:
Performance Considerations
Query Cost: Computing paths requires one additional query per document to fetch all ancestors. For example, loading 50 folder documents will make 51 queries (1 for the folders, 1 for ancestors).
Request-Scoped Caching: Ancestors are cached within each request, so if multiple documents share the same parent, the parent is only fetched once:
Recommendation: Only request paths when you need them for URLs or breadcrumbs. Skip path computation when loading related documents if paths aren't used.
Configuration
Basic Configuration
Enable with defaults (parent field auto-created):
With Custom Parent Field
Define the parent field yourself for custom validation or UI:
With Custom Options
Config Options
Option | Type | Required | Description |
|---|---|---|---|
| | Yes | Name of the parent relationship field. Will be auto-created if it doesn't exist. |
| | No | Collection(s) that can be used as parents. Single string for monomorphic (same collection), array for polymorphic (multiple collections). Defaults to self-referential. |
| | No | Custom function to slugify text for path generation. Default uses basic slugify. |
| | No | Name for the virtual slugified path field. Default: |
| | No | Name for the virtual title path field. Default: |
Polymorphic Hierarchies
Basic Example
This enables organizing content like:
Creating Documents with Polymorphic Parents
When creating a document with a polymorphic parent, specify both the collection and ID:
Path Computation
Paths are computed across collections automatically:
Use Cases
Blog Posts Under Pages
Result: Blog section can be a page with posts nested underneath, posts can have threaded replies.
Products Under Categories
Result: Categories form the main tree, products nest within categories, product variants can nest under products.
Mixed Content Tree
Result: Flexible organization where pages are top-level, folders and documents can nest under pages or folders.
Important Behaviors
Circular Reference Protection
Circular reference detection works across collections:
Draft and Localization
Polymorphic hierarchies fully support drafts and localization:
- Drafts: Path computation follows draft context across collections
- Localization: Paths computed per locale using each collection's localized title fields
Target Collection Requirements
When using relationTo with multiple collections:
- Target collections should also have hierarchy enabled
- Target collections must exist in the config
- If a target collection doesn't have hierarchy enabled, you'll see a warning (but it will still work for simple parent relationships)
Limitations
Parent Field Cannot Be Localized
The parent field stores the relationship and must be consistent across all locales. This means:
- ✅ Tree structure is the same across all locales
- ✅ Path titles can differ per locale
- ❌ Cannot have different parent relationships per locale
Manual Parent Field
If you manually define the parent field for a polymorphic hierarchy:
Use Cases
Nested Pages
Nested Categories
Organizational Structure
Localization Support
If the title field (from admin.useAsTitle) is localized, path fields are automatically localized:
Result:
How It Works
Parent Relationship Management
Hierarchy maintains parent-child relationships through a simple parent field:
- Validates there are no circular references when parent changes
- Cleans up orphaned children when a parent is deleted (sets their parent to null)
- No cascade updates needed - paths are always computed fresh
Example:
Path Computation
Path fields are computed on-demand when requested:
- Walk Parent Chain: Recursively follows
parentrelationships to root - Build Paths: Concatenates titles/slugs from ancestors in correct order
- Cache Results: Ancestors cached in
req.contextfor the request duration - Localization: Paths computed per locale if title field is localized
Title Change Behavior:
When you change a document's title, paths are automatically updated on the next read—no cascade updates needed:
No descendants are updated in the database—paths always reflect current ancestor titles.
Important Behaviors
No Cascade Updates
When you move or rename a document, descendants are not updated:
- ✅ Only parent field updated - The document's
parentfield is changed - ✅ No descendant updates - Children and descendants are not touched
- ✅ Paths always accurate - Paths computed fresh on read always reflect current hierarchy
Performance Benefit: Moving or renaming documents is fast regardless of how many descendants exist.
Example:
Circular Reference Protection
Hierarchy automatically prevents circular references. You cannot:
- Set a document as its own parent
- Set a descendant as a parent (e.g., grandchild → parent → grandchild)
These operations will throw an error before any changes are made.
Draft Version Handling
When versioning with drafts is enabled, paths are computed based on the current read context:
- ✅ Draft context - Paths computed using draft parent and draft title
- ✅ Published context - Paths computed using published parent and published title
- ✅ Always accurate - Paths always reflect the correct version's data
Example:
How it works:
- When computing paths, hierarchy fetches ancestors using the same
draftcontext - If reading a draft, ancestor titles come from draft versions (if they exist)
- If reading published, ancestor titles come from published versions
- This ensures paths always reflect the correct version's hierarchy state
No Cascade Updates Needed:
Unlike stored paths, computed paths don't require updating draft versions when a parent changes. Paths are always accurate because they're computed from the current version's tree structure.
Limitations
Locale 'all' Not Supported
Updates with locale: 'all' will skip hierarchy processing. Workaround: Update each locale individually.
Parent Changes When Publishing a Single Locale
Use with caution: When publishing a single locale (locale: '<code>' with _status: 'published'), be aware that the parent field is not localized—tree structure must be consistent across locales.
When you publish a draft with a changed parent for one locale:
- The parent change applies to all locales (parent field is not localized)
- Paths are computed per locale on next read
- Each locale's paths will reflect the new parent combined with that locale's titles
Example:
Recommendation: When moving documents in the hierarchy (changing parent), prefer publishAllLocales (default) to make the intent clear:
Note: Title changes work as expected when publishing a single locale, since paths are computed per locale.
Best Practices
Use Consistent Title Fields
Ensure your admin.useAsTitle field is stable and always has a value:
Avoid: Fields that can be empty, computed fields, or fields nested in named groups/tabs.
Consider Performance at Scale
For collections with many documents:
- Only request paths when needed - Use
computeHierarchyPaths: trueonly for UI/breadcrumb display - Skip paths for relationships - When loading related documents, omit path computation to avoid extra queries
- Limit tree depth - Deep trees (10+ levels) will have slower path computation
- Leverage caching - Multiple documents sharing ancestors benefit from request-scoped caching
Example optimization:
TypeScript
The hierarchy fields are automatically included in your generated types:
Note: Virtual path fields (_h_slugPath, _h_titlePath) are included in generated types but will be undefined at runtime unless you request path computation.
If types aren't generated, regenerate them:
Was this page helpful?