Why use joins?
Reduce data duplication
Store company details once; reference from many deals instead of embedding full objects in each deal document.
Faster indexing
Smaller documents mean faster indexing operations and reduced storage requirements.
Keep data normalized
Update company information once and it’s automatically reflected in all deal queries.
Flexible queries
Hydrate related data when needed and filter by related document properties without denormalization.
How relationships work
A relationship connects a source index to a target index using foreign key fields. For example, a document in thedeals index references a document in the companies index through a company_id field:
Deals index
Companies index
company_id with the full company object.
Define a relationship
Configure foreign keys and filterable attributes in the source index settings:Configuration parameters
| Parameter | Type | Description | Example |
|---|---|---|---|
fieldName | string | Field in the source index containing the ID(s) | "company_id" or "actor_ids" |
foreignIndexUid | string | UID of the target index | "companies" or "actors" |
attributePatterns | array | Field patterns to make filterable | ["company_id"] |
features | object | Filter capabilities (equality, comparison, facetSearch) | {"filter": {"equality": true}} |
Relationship types
One-to-one
Each source document has exactly one related target document. Example: Users → Profiles (each user has one profile)One-to-many
Each source document has multiple related target documents, stored as an array of IDs. Example: Companies → Employees (one company has many employees)Many-to-many
Multiple source documents reference multiple target documents, typically using array fields. Example: Films → Actors (one film has many actors, many films feature the same actor)Self-references
You can create relationships where a document references other documents in the same index. This is useful for modeling hierarchical or interconnected data. Example: Products frequently bought togetherMultiple relationships
Configure multiple foreign keys in a single settings update:Update relationships
To replace an existing relationship, provide the updated configuration:Depth limitation
Joins support hydration and filtering at one level only. You cannot create nested chains like deals → companies → industry_details. Each hydration or filter operates on a direct relationship between two indices.Data integrity
Meilisearch does not enforce referential integrity. You can create foreign key references to non-existent documents, and deleting a target document does not affect documents that reference it. When a referenced document is deleted:- Hydration returns the document UID instead of the full object
- Filtering ignores the reference in filter comparisons
Cleanup strategy
You can handle orphaned references in two ways: delete the source documents entirely, or remove the orphaned IDs from the foreign key fields.Delete source documents
Use the delete by filter API to remove source documents that reference non-existent targets:Remove orphaned IDs with functions
Use edit documents by function to remove specific orphaned IDs from array foreign key fields without deleting the source documents. This is useful for many-to-many relationships where only some referenced IDs are orphaned. For example, remove a deleted actor from theactors array in all film documents:
Next steps
Foreign filters
Filter documents by properties of related data across indices
Precise array filtering
Use AND logic to filter array relationships with joins
RBAC with joins
Implement role-based access control using joins and tenant tokens
Indexing best practices
Learn best practices including how joins reduce index size