Reference properties
How to define reference properties so a content item can point at other content items, and how to resolve them in a query.
A reference property points from one content item to another. Optimizely Graph resolves the reference at query time. One query returns the item you requested and the content it references, so you skip the second lookup.
Use a reference property when a property in your content model points at another item. Examples include a page's hero image, a start page's featured products, and a category's parent category. Use joins with linking instead to discover relationships that your content model does not express as pointers. For a side-by-side comparison, see Choose between a reference and a link.
Working with a reference property takes three steps:
- Define the
refobject on the property. - Send the target identifier in the content data.
- Select the property in a query.
Prerequisites
Before you define a reference property, make sure you have the following:
- A content source registered with Optimizely Graph.
- A content types definition that you control.
- Credentials for the sync API.
Define a reference property
One ref definition makes the property resolvable in every query against the content type. Add a ref object to a property in your content types definition. The ref object tells Optimizely Graph what to resolve the stored value into.
{
"contentTypes": {
"StartPage": {
"properties": {
"ProductSingleRef": {
"type": "IProduct",
"ref": { "type": "Product", "id": "_id" }
},
"ProductMultiRef": {
"type": "[IProduct]",
"ref": { "type": "Product", "id": "_id" }
}
}
}
}
}The ref object accepts two optional keys.
| Key | Required | Description |
|---|---|---|
ref.type | No | The content type to resolve the reference into. Defaults to the property's own type. If that type is an interface (such as IProduct), Optimizely Graph resolves it to the matching concrete type (Product). |
ref.id | No | The property on the referenced content type that holds the identifier. Defaults to _id, the identifier Optimizely Graph assigns to every indexed document. |
The property's own type controls the shape of the result:
"type": "IProduct"– a single reference. The query returns one object."type": "[IProduct]"– multiple references. The query returns a list of objects.
Omit ref.type to fall back to the declared type. The following example resolves against Data, the root type that every content type derives from. It matches on a custom identifier property named Id instead of _id:
"ProductCustomRef": {
"type": "[IData]",
"ref": { "id": "Id" }
}
NoteA reference that points at nothing is not an error. It returns an empty object (
{}) for a single reference, or an empty list ([]) for multiple references.
Send reference values in content data
Optimizely Graph matches the identifier you send against the target item, so the two documents stay independent in the index. The value you send for a reference property is the identifier of the target item, not a nested object. Send a string for a single reference and an array of strings for multiple references. Each value must match the value of the ref.id property on the item you are pointing at.
Given the previous StartPage definition, sync the content data like this:
{
"ContentType": ["Content", "StartPage"],
"__typename": "StartPage",
"Name___searchable": "StartPage title",
"ProductSingleRef": "shopify_item_3",
"ProductMultiRef": ["shopify_item_2", "shopify_item_4", "shopify_item_1"]
}The referenced products are separate documents, indexed on their own:
{
"ContentType": ["ShopifyProduct", "Product", "Catalog"],
"__typename": "ShopifyProduct",
"_id": "shopify_item_3",
"Name___searchable": "Shopify Product 3",
"Color": "Green",
"Size": 38,
"Quantity": 5
}You do not have to index the referenced item before the item that points at it. Optimizely Graph resolves references at query time, so the order in which you sync the two items does not matter.
The referenced item lives in any source. A source is a registered origin of content, such as a CMS instance or an external system. Optimizely Graph resolves cross-source references automatically. No extra configuration applies, and the reference field takes no source argument.
Query a reference
One query returns the parent item and its referenced content together, so the client makes a single round trip. Select the reference property as if it were a nested content type. Because the declared type is usually an interface, use an inline fragment to select the fields of the concrete type.
{
StartPage {
items {
Name
ProductSingleRef {
... on ShopifyProduct {
Name
Color
Size
}
}
ProductMultiRef {
... on ShopifyProduct {
Name
Color
Size
}
}
}
}
}The single reference returns an object and the multiple reference returns a list, in the order you sent the identifiers:
{
"data": {
"StartPage": {
"items": [
{
"Name": "StartPage title",
"ProductSingleRef": {
"Name": "Shopify Product 3",
"Color": "Green",
"Size": 38
},
"ProductMultiRef": [
{ "Name": "Shopify Product 2", "Color": "Blue", "Size": 36 },
{ "Name": "Shopify Product 4", "Color": "Yellow", "Size": 40 },
{ "Name": "Shopify Product 1", "Color": "Red", "Size": 42 }
]
}
]
}
}
}A reference property carries a reference table in its field description showing the resolved type and id. Open the Docs tab on the GraphiQL page and select the property. The table confirms the target type and the matching property, so you do not open the content types definition.

The example declares ProductMultiRef as [IProduct]. The table confirms that Optimizely Graph resolves it into Product by matching on _id.
ContentReference property type
ContentReference property typeOptimizely CMS (SaaS) exposes references through a shared property type, so one definition serves every content type. Instead of putting ref directly on the content type property, CMS (SaaS) uses a shared property type named ContentReference. That type wraps the reference in an object alongside other data about the target:
{
"propertyTypes": {
"ContentReference": {
"properties": {
"key": { "type": "String", "index": true },
"url": { "type": "ContentUrl", "index": true },
"item": { "type": "IData", "ref": { "type": "Data", "id": "_id" } }
}
}
}
}The ref sits on the inner item property. key and url are ordinary indexed properties that you read without resolving anything. item holds the reference that Optimizely Graph resolves into the referenced content.
Content types then use ContentReference as a normal property type, either singly or as a list:
"StartPage": {
"properties": {
"Image": { "type": "ContentReference", "index": true },
"ImageList": { "type": "[ContentReference]", "index": true }
}
}In the content data, each ContentReference is an object. The item property carries the identifier of the target:
{
"Image": {
"key": "Image_1",
"item": "Image_1",
"__typename": "ContentReference"
},
"ImageList": [
{ "key": "Image_2", "item": "Image_2", "__typename": "ContentReference" },
{ "key": "Image_3", "item": "Image_3", "__typename": "ContentReference" }
]
}Query key and url directly, and go through item to reach the referenced content. Note that ImageList is a list of references, but each entry still exposes a single item:
{
StartPage {
items {
Image {
key
item {
_id
... on cmp_Asset {
Name
Url
}
}
}
ImageList {
key
item {
_id
... on cmp_Asset {
Name
Url
}
}
}
}
}
}Selecting only key does not resolve anything, so it costs nothing beyond the parent query. Add item only when you need fields from the referenced content.
Limit the number of resolved items
Raise the resolution cap when a query returns more parent items than the default lookup covers. Optimizely Graph resolves the references for every item in the parent result set with a single batched lookup. For single references, that lookup returns at most 10 items by default. A query that returns more than 10 parent items leaves the extra references unresolved.
Change the cap with the maxSubRequestSize variable, up to a maximum of 100. Send it in the variables payload of the GraphQL request. Do not declare it in the operation. Optimizely Graph reads it from the request variables, and GraphQL rejects a declared variable that the operation never uses.
{
"query": "{ StartPage { items { ProductSingleRef { ... on ShopifyProduct { Name } } } } }",
"variables": { "maxSubRequestSize": 50 }
}The cap behaves as follows at its boundaries:
- A value above 100 returns the error
maxSubRequestSize must be less than or equal to 100. - A value below one resolves nothing.
- The cap does not apply to multiple references. Optimizely Graph ignores
maxSubRequestSizefor a list-typed reference property, and returns no error when you set it above 100.
Cache invalidation for resolved references
Optimizely Graph tags a cached response with the identifier of every published item the query resolved. That set covers the referenced items and the items you queried directly. Editing a referenced item invalidates the cached response of any query that pointed at it. Stale content never reaches the reader.
Cache tagging applies only to published items. Unpublished referenced content contributes no cache tag.
Reference property limitations
Optimizely Graph resolves reference properties in a separate lookup against the referenced content. The following restrictions follow from that design.
- Filter, sort, and facet arguments – Optimizely Graph does not add the property that carries the
reftowhere,orderBy,facets, orautocomplete. Filter on the referenced content type in its own query, or model the value as an ordinary property.keyandurlon theContentReferenceproperty type stay filterable. - Highlight – A reference property never highlights, even when you mark it as
searchable. - Nested references – A reference property inside a resolved reference returns an error. References resolve one level deep.
_linkinside a reference – Combine joins and references at the same level instead of nesting one inside the other.- Query cost – Optimizely Graph costs a reference like a link. A query that resolves several references costs more than the same query without them. Check the
costSummaryin the responseextensionsfor the breakdown.
Choose between a reference and a link
Both features connect content items, but they solve different problems.
| Characteristic | Reference property | _link |
|---|---|---|
| Modeled as | A property on the content type that holds a pointer | A named link type defined once at the root of the source |
| Direction | From the item that stores the identifier to the item it names | Either direction, wherever the from and to values match |
| Result shape | Nested under the property name | Nested under _link, grouped by content type |
| Depth | One level | Up to three levels |
| Best for | Deliberate pointers in your content model, such as an image or a related product | Discovering relationships across content types by matching values, such as tags or authors |
Updated about 2 hours ago
