5.7 KiB
| title | aliases | tags | sources | created | updated | |||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Relationship Field |
|
|
|
2026-05-15 | 2026-05-15 |
One of the most powerful Payload fields — links documents across collections, supports polymorphic (multi-collection) references, and works with the wiki/payloadcms/fields-join for bi-directional authoring.
Config Options
import type { Field } from 'payload'
export const MyRelationshipField: Field = {
name: 'owner',
type: 'relationship',
relationTo: 'users', // string or string[] for polymorphic
hasMany: false, // true = array of relations
}
| Option | Notes |
|---|---|
relationTo * |
Collection slug(s) — array = polymorphic |
hasMany |
true → array mode |
minRows / maxRows |
Validation for hasMany |
filterOptions |
Where query or function to limit selectable docs |
maxDepth |
Override global populate depth for this field |
unique |
DB-level unique index |
localized |
Per-locale separate relation values |
Admin Options
| Property | Notes |
|---|---|
isSortable |
Drag-and-drop reorder (requires hasMany: true) |
allowCreate |
Disable inline doc creation (default: true) |
allowEdit |
Disable inline doc edit (default: true) |
appearance |
'select' (default) or 'drawer' |
sortOptions |
String or { collectionSlug: 'fieldName' } — prefix - for desc |
placeholder |
Custom placeholder text or function |
Data Shapes
Has One (single collection)
Config: relationTo: 'users', hasMany: false
{ "owner": "6031ac9e1289176380734024" }
Query: ?where[owner][equals]=6031ac9e1289176380734024
Has One — Polymorphic (multiple collections)
Config: relationTo: ['users', 'organizations'], hasMany: false
{
"owner": {
"relationTo": "organizations",
"value": "6031ac9e1289176380734024"
}
}
Query by value: ?where[owner.value][equals]=6031ac9e1289176380734024
Query by collection: ?where[owner.relationTo][equals]=organizations
Has Many (single collection)
Config: relationTo: 'users', hasMany: true
{ "owners": ["6031ac9e1289176380734024", "602c3c327b811235943ee12b"] }
Query: ?where[owners][equals]=6031ac9e1289176380734024
Has Many — Polymorphic
Config: relationTo: ['users', 'organizations'], hasMany: true
{
"owners": [
{ "relationTo": "users", "value": "6031ac9e1289176380734024" },
{ "relationTo": "organizations", "value": "602c3c327b811235943ee12b" }
]
}
Query: ?where[owners.value][equals]=6031ac9e1289176380734024
Filtering Relationship Options
filterOptions: ({ relationTo, siblingData, data, id, req, user }) => {
if (relationTo === 'products') {
return { stock: { greater_than: siblingData.quantity } }
}
return true // no filter
}
- Return
Wherequery,true(no filter), orfalse(block all) - Used for both UI filtering AND server-side validation
- Gotcha: if you also provide a custom
validatefunction, call the default Payload validator frompayload/sharedinside it — otherwisefilterOptionsis not enforced on the backend
Bi-directional Relationships
The Relationship field alone is one-way (the related document has no back-reference). Use wiki/payloadcms/fields-join on the related collection to add a virtual reverse lookup without storing extra data.
Polymorphic Query Limitation
You cannot query on a field within a related document when the relationship is polymorphic.
Only field.value (doc ID) and field.relationTo (collection slug) are safe to query. Filtering by a sub-field (e.g. field.name) breaks because that field may not exist across all related collections.
Auto-population via Depth
Use the wiki/payloadcms/queries query param to automatically populate related documents in API responses:
?depth=1→ expand one level of relationshipsmaxDepthon the field overrides the remaining depth
Custom Components
Field (Server)
import { RelationshipField } from '@payloadcms/ui'
import type { RelationshipFieldServerComponent } from 'payload'
export const CustomRelationshipFieldServer: RelationshipFieldServerComponent =
({ clientField, path, schemaPath, permissions }) => (
<RelationshipField field={clientField} path={path} schemaPath={schemaPath} permissions={permissions} />
)
Field (Client)
'use client'
import { RelationshipField } from '@payloadcms/ui'
import type { RelationshipFieldClientComponent } from 'payload'
export const CustomRelationshipFieldClient: RelationshipFieldClientComponent =
(props) => <RelationshipField {...props} />
Key Takeaways
relationToas a string array = polymorphic — data shape changes to{ relationTo, value }wrapper- Polymorphic data is always
{ relationTo, value }— even forhasMany: false - Polymorphic querying: only
field.value(ID) andfield.relationTo(slug) — never sub-fields hasMany: true+ single collection → flat ID array;hasMany: true+ polymorphic → array of{ relationTo, value }objects- Use wiki/payloadcms/fields-join for reverse/bi-directional lookup (zero DB overhead)
filterOptionsfilters both UI dropdown and server-side validation — but only if default validator is called when a customvalidateis presentadmin.isSortablerequireshasMany: trueadmin.appearance: 'drawer'is better for large-document relationships
Sources
raw/fields__relationship.md— https://payloadcms.com/docs/fields/relationship