Strapi 5 plugin for polymorphic relations - select any content type and entity in one field with inverse relation support
npm install @sivium/strapi-plugin-polymorphic-relationsA powerful Strapi 5 plugin that adds true polymorphic relations to your content types, allowing you to reference any content type from a single field.


- Polymorphic Relations: Select any content type and entity from a single field
- Inverse Relations: Automatically show reverse relationships (e.g., "which posts reference this category?")
- Standard Populate Support: Works seamlessly with Strapi's populate query parameter
- Flexible Relation Types: Choose between "Has One" or "Has Many" for both regular and inverse relations
- Auto-Population: Automatically resolves relations in API responses
- TypeScript Support: Full TypeScript definitions included
- Strapi 5 Compatible: Built specifically for Strapi 5 with modern architecture
``bash`
npm install @sivium/strapi-plugin-polymorphic-relationsor
yarn add @sivium/strapi-plugin-polymorphic-relationsor
pnpm add @sivium/strapi-plugin-polymorphic-relations
Add the plugin to your config/plugins.ts:
`typescript`
export default {
'polymorphic-relation': {
enabled: true,
},
};
1. Open Content-Type Builder
2. Select a content type
3. Click Add another field
4. Choose Custom → Polymorphic Relation
5. Configure your field options
The field will appear as two dropdowns:
1. Select the content type (e.g., "Article", "Product", "Page")
2. Select the specific entry
Allows you to reference any content type from a single field.
Configuration Options:
- Allowed Content Types: Comma-separated UIDs (e.g., api::post.post, api::product.product)Has One (Single)
- Relation Type:
- - Single referenceHas Many (Multiple)
- - Array of referencestitle
- Display Field: Field to show in the selector (default: )
API Response (without populate):
`json`
{
"myField": {
"contentType": "api::post.post",
"id": "abc123"
}
}
API Response (with populate):
`json`
{
"myField": {
"__contentType": "api::post.post",
"id": 1,
"documentId": "abc123",
"title": "My Post",
...
}
}
Shows which entries reference the current entry (read-only, computed field).
Configuration Options:
- Target Model UID: The model to search (e.g., api::post.post)Has One (Single)
- Target Field Name: The polymorphic field name in the target model
- Relation Type:
- - Returns single objectHas Many (Multiple)
- - Returns array
- Target Display Field: Field to display from target entries
- Label: Custom label for the field
Example Use Case:
If you have a Category content type and Posts that reference categories via a polymorphic field called category, you can add an inverse relation to Category to show all posts that reference it.
API Response (without populate):
`json`
{
"relatedPosts": [{ "id": "post1" }, { "id": "post2" }]
}
API Response (with populate):
`json`
{
"relatedPosts": [
{
"id": 1,
"documentId": "post1",
"title": "First Post",
"category": { ... }
}
]
}
The plugin respects Strapi's standard populate query parameter:
`bash`
GET /api/posts
`json`
{
"myPolymorphicField": {
"contentType": "api::category.category",
"id": "abc123"
},
"inverseField": [{ "id": "xyz789" }]
}
`bash`
GET /api/posts?populate=*
`json`
{
"myPolymorphicField": {
"__contentType": "api::category.category",
"id": 1,
"documentId": "abc123",
"name": "Technology",
...
},
"inverseField": [
{
"id": 1,
"documentId": "xyz789",
"title": "Related Item",
...
}
]
}
`bash`
GET /api/posts?populate[myPolymorphicField]=*
`bash`
GET /api/posts?populate[myPolymorphicField][populate]=author
The plugin supports filtering by fields within the polymorphic relation, even without populate. This is handled via pre-processing middleware that resolves relationships before the main query.
Filter by a specific field in the related entity:
`bash`
GET /api/articles?filters[myPolymorphicField][title][$eq]=My Article
Combine multiple filters on the polymorphic relation:
`bash`
GET /api/articles?filters[myPolymorphicField][title][$containsi]=tech&filters[myPolymorphicField][isPublished][$eq]=true
You can filter and populate at the same time:
`bash`
GET /api/articles?populate=myPolymorphicField&filters[myPolymorphicField][title][$eq]=My Article
Configure the plugin in config/plugins.ts:
`typescript
export default {
'polymorphic-relation': {
enabled: true,
config: {
// Whitelist of allowed content types (empty = all allowed)
allowedTypes: ['api::post.post', 'api::product.product', 'api::page.page'],
// Blacklist of ignored content types
ignoredTypes: ['plugin::users-permissions.user', 'admin::user'],
},
},
};
`
Each field can override global settings:
Regular Polymorphic Relation:
- allowedTypes: Comma-separated UIDs to restrict choicesrelationType
- : one or manydisplayField
- : Field to display in selector
Inverse Polymorphic Relation:
- targetModel: UID of the model to searchtargetField
- : Name of the polymorphic field in target modelrelationType
- : one or manytargetDisplayField
- : Field to display from resultslabel
- : Custom label for the field
`typescript`
// A "Hero Section" that can reference any content type
{
"heroContent": {
"contentType": "api::product.product",
"id": "featured-product-123"
}
}
`typescript`
// "You might also like" section with mixed content types
{
"relatedItems": [
{ "contentType": "api::post.post", "id": "post-1" },
{ "contentType": "api::video.video", "id": "video-1" },
{ "contentType": "api::product.product", "id": "product-1" }
]
}
`typescript`
// Show all content that references this category
{
"usedIn": [
{ "id": 1, "title": "Blog Post", "__contentType": "api::post.post" },
{ "id": 5, "title": "Product", "__contentType": "api::product.product" }
]
}
The plugin provides REST endpoints for the admin panel:
- GET /api/polymorphic-relation/content-types - List available content typesGET /api/polymorphic-relation/content-types/:type/entities
- - List entities for a typeGET /api/polymorphic-relation/content-types/:type/entities/:id
- - Get specific entityGET /api/polymorphic-relation/reverse-relations
- - Find reverse relations
`bash`
npm run build
`bash`
npm run watch
`bash`
npm run verify
The plugin includes full TypeScript definitions:
`typescript
import type {
PolymorphicValue,
ResolvedPolymorphicValue,
} from 'strapi-plugin-polymorphic-relations/server';
// Polymorphic value stored in database
interface PolymorphicValue {
contentType: string;
id: string;
}
// Resolved value with full entity data
interface ResolvedPolymorphicValue {
__contentType: string;
id: number;
documentId: string;
[key: string]: any;
}
`
Contributions are welcome! Please feel free to submit a Pull Request.
1. Fork the repository
2. Create your feature branch (git checkout -b feature/AmazingFeature)git commit -m 'Add some AmazingFeature'
3. Commit your changes ()git push origin feature/AmazingFeature`)
4. Push to the branch (
5. Open a Pull Request
MIT License - see the LICENSE file for details.
Developed by Sivium Solutions
- 🐛 Report a Bug
- 💡 Request a Feature
- 📖 Documentation
- npm Package
- GitHub Repository
- Strapi Documentation
---
Made with ❤️ for the Strapi community