HomeDev GuideRecipesAPI Reference
Dev GuideAPI ReferenceUser GuideGitHubNuGetDev CommunityOptimizely AcademySubmit a ticketLog In
Dev Guide

CMS 13 and 12 Graph comparison

CMS 13 introduces a unified, inheritance-based GraphQL schema for Optimizely Graph that changes how you query content, metadata, and referenced properties. Use this comparison to identify the query and output differences between Content Management System (CMS) 13 and CMS 12 and update your queries before upgrading.

This article covers the following areas:

  • Content type structure differences.
  • GraphQL schema differences.
  • Property structure comparisons with query and response examples.
  • Experience-based content queries.
  • Content Graph feature comparison.
🚧

Important

The schema changes described in this article are breaking changes when you upgrade from CMS 12 to CMS 13. Review each section and update your queries before deploying.

Content type comparison

The following table compares content type support in CMS 12 and CMS 13.

Content TypeCMS 12CMS 13
PageTypeSupportedSupported
BlockTypeSupportedSupported
MediaTypeImage, Video, GenericMediaImage, Video, GenericMedia
ExperienceNot supportedSupported
SectionNot supportedSupported

GraphQL schema comparison

CMS 13 restructures the GraphQL schema to use a unified, inheritance-based model instead of the flat, per-type approach in CMS 12.

Both versions support standard GraphQL features, including queries with cursor, ids, limit, locale, skip, orderBy, pinned, where, facets, _fulltext, _and, _or, _not, _link, _children, _score, _json, _track, __modified, and _deleted.

The following list describes the key differences:

  • CMS 12 exposes each content type as a separate root-level query.
  • CMS 13 uses a unified, inheritance-based schema and adds support for _metadata, Experiences, external sources, and Variations.
  • CMS 13 changes property query structures and output formats.
  • CMS 13 removes support for SiteId and SiteDefinition queries. Use _metadata.url.base to return content that belongs to a specific site.

CMS 13 defines base schema types (prefixed with _):

_Content, _Page, _Component, _Media, _Folder, _Experience, _Image, _Video, _Section, _Item, _AssetItem, _ImageItem.

Custom content types inherit from these base types. The following list describes examples of inheritance:

  • A page type (NewsPage) inherits from _Page.
  • A block type (TeaserBlock) inherits from _Component.
  • Both _Page and _Component inherit from _Content.

This inheritance model produces a consistent and extensible schema that enables uniform queries across content types.

Property query comparison

Use the following sections to understand how property queries differ between CMS 12 and CMS 13. Each section includes side-by-side queries and response examples.

Metadata properties

The following table compares equivalent metadata properties between CMS 12 and CMS 13. CMS 13 exposes metadata through the unified _metadata object, whereas CMS 12 exposes similar information through dedicated fields.

CMS 12CMS 13
ContentLink { GuidValue }_metadata { key }
Language { Name }_metadata { locale }
ExistingLanguages { Name }_metadata { locales }
ContentLink { WorkId }_metadata { version }
ContentType_metadata { types }
Name_metadata { displayName }
StartPublish_metadata { published }
StopPublish_metadata { expired }
Status_metadata { status }
ParentLink { Id }_metadata { container }
Url_metadata { url { base, default, graph, hierarchical, internal, type } }
RouteSegment_metadata { routeSegment }
Not available_metadata { path }
Not available_metadata { owner }
Not available_metadata { ... on InstanceMetadata { expired } }
Not available_metadata { ... on InstanceMetadata { lastModifiedBy } }
Not available_metadata { ... on InstanceMetadata { createdBy } }

Sample query comparison for metadata (IContentMetadata)

CMS 12 query:

query MyQuery {
  Content(where: { Name: { eq: "Start2" } }) {
    items {
      ContentLink {
        GuidValue
        Id
        WorkId
        Url
      }
      Language {
        Link
        DisplayName
        Name
      }
      Name
      StartPublish
      Status
      Created
      Changed
      _sortOrder
      ContentType
      Url
    }
  }
}

CMS 13 query:

query MyQuery {
  _Content(where: { _metadata: { displayName: { eq: "Start2" } } }) {
    items {
      _metadata {
        key
        locale
        version
        displayName
        published
        status
        changeset
        created
        lastModified
        sortOrder
        variation
        types
        url {
          type
          default
          hierarchical
          internal
          graph
          base
        }
      }
    }
  }
}

CMS 12 result:

{
  "data": {
    "Content": {
      "items": [
        {
          "ContentLink": {
            "GuidValue": "337c7c36-1998-4a64-b3e1-ea4e544fdf76",
            "Id": 1405,
            "WorkId": 1704,
            "Url": "https://localhost:8039/en/start2/"
          },
          "Language": {
            "Link": "https://localhost:8039/en/start2/",
            "DisplayName": "English",
            "Name": "en"
          },
          "Name": "Start2",
          "StartPublish": "2025-11-05T03:33:17Z",
          "Status": "Published",
          "Created": "2025-11-05T03:33:10Z",
          "Changed": "2025-11-05T03:33:17Z",
          "_sortOrder": 1700,
          "ContentType": ["Page", "StartPage", "Content"],
          "Url": "https://localhost:8039/en/start2/"
        }
      ]
    }
  }
}

CMS 13 result:

{
  "data": {
    "_Content": {
      "items": [
        {
          "_metadata": {
            "key": "f565ddf42213425390fdbad7147d2a06",
            "locale": "en",
            "version": "8",
            "displayName": "Start2",
            "published": "2025-11-24T04:14:09.698Z",
            "status": "Published",
            "changeset": "default",
            "created": "2025-11-24T04:13:53.504Z",
            "lastModified": "2025-11-24T04:14:09.698Z",
            "sortOrder": 0,
            "variation": null,
            "types": ["StartPage", "_Page", "_Content", "_Item"],
            "url": {
              "type": "HIERARCHICAL",
              "default": "/en/start2/",
              "hierarchical": "/en/start2/",
              "internal": "cms://content/f565ddf42213425390fdbad7147d2a06?loc=en&ver=8",
              "graph": "graph://cms/StartPage/f565ddf42213425390fdbad7147d2a06",
              "base": "https://localhost:8001"
            }
          }
        }
      ]
    }
  }
}

CMS 13 removes support for SiteId and SiteDefinition queries. Scope queries to a site by filtering on _metadata.url.base to return content that belongs to the specified hostname.

The following query demonstrates site-scoped filtering:

query {
  _Content(
    where: {
      _metadata: { 
        url: { 
          base: { eq: "https://site-a.com" }
        }
      }
    }
  ) {
    items {
      _id
      _metadata {
        url {
          base
        }
      }
    }
  }
}

CMS 13 structures metadata into different scopes to separate content lifecycle, content identity, and media-specific information.

InstanceMetadata

Use InstanceMetadata when you query standalone content instances such as pages and blocks. Cast _metadata to InstanceMetadata to access instance-level details that extend IContentMetadata with the following properties:

  • container – The key of the content item that contains this item.
  • owner – The key of the owning content item when the content is an asset of another content item.
  • path – The hierarchy of containers for this item.

InstanceMetadata query example:

query MyQuery {
  _Content(where: { _metadata: { displayName: { eq: "Start2" } } }) {
    items {
      _metadata {
        displayName
        ... on InstanceMetadata {
          routeSegment
          container
          createdBy
          expired
          lastModifiedBy
          locales
          owner
          path
        }
      }
    }
  }
}

InstanceMetadata result:

{
  "data": {
    "_Content": {
      "items": [
        {
          "_metadata": {
            "displayName": "Start2",
            "routeSegment": "start2",
            "container": "dd3adb7ae0884449a1eed6c7f1dffdef",
            "createdBy": "[email protected]",
            "expired": null,
            "lastModifiedBy": "[email protected]",
            "locales": ["en"],
            "owner": null,
            "path": [
              "dd3adb7ae0884449a1eed6c7f1dffdef",
              "f565ddf42213425390fdbad7147d2a06"
            ]
          }
        }
      ]
    }
  }
}

ItemMetadata

Use ItemMetadata for content items that appear inside a container, such as entries in a ContentArea. Cast _metadata to ItemMetadata to access properties such as displayOption that extend IContentMetadata.

ItemMetadata query example:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage3" } } }) {
    items {
      _metadata {
        displayName
        key
      }
      ContentArea {
        _metadata {
          ... on ItemMetadata {
            displayOption
            locale
            key
          }
        }
      }
    }
  }
}

ItemMetadata result:

{
  "data": {
    "StandardPage": {
      "items": [
        {
          "_metadata": {
            "displayName": "StandardPage3",
            "key": "0076eb95f7e0425ea082197d2bb039a8"
          },
          "ContentArea": [
            {
              "_metadata": {
                "displayOption": null,
                "locale": "en",
                "key": "f565ddf42213425390fdbad7147d2a06"
              }
            },
            {
              "_metadata": {
                "displayOption": null,
                "locale": "en",
                "key": "b8a60749ef584cedbaf111a4f93ae15d"
              }
            }
          ]
        }
      ]
    }
  }
}

MediaMetadata

Use MediaMetadata for media content such as images, videos, and other media files. Cast _metadata to MediaMetadata to access properties such as container, mimeType, and thumbnail that extend IContentMetadata.

MediaMetadata query example:

query MyQuery {
  _Content(where: { _metadata: { displayName: { eq: "Image1.png" } } }) {
    items {
      _metadata {
        displayName
        ... on MediaMetadata {
          container
          content
          createdBy
          expired
          lastModifiedBy
          locales
          mimeType
          owner
          path
          routeSegment
          thumbnail
        }
      }
    }
  }
}

MediaMetadata result:

{
  "data": {
    "_Content": {
      "items": [
        {
          "_metadata": {
            "displayName": "Image1.png",
            "container": "e56f85d0e8334e02976a2d11fe4d598c",
            "content": "A beautiful picture",
            "createdBy": "[email protected]",
            "expired": null,
            "lastModifiedBy": "[email protected]",
            "locales": [],
            "mimeType": "image/png",
            "owner": null,
            "path": ["aabdb22fd36c4044af0b14cc31efb292"],
            "routeSegment": "Image1",
            "thumbnail": "https://app-sactmain242x8byp001.cmstest.optimizely.com/globalassets/Image1//thumbnail"
          }
        }
      ]
    }
  }
}

Standard primitive properties

Standard primitive property types such as String, Int, Boolean, DateTime, Float, Guid, and Choice use the same query syntax and return responses in a consistent format across both versions.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage3" } }) {
    items {
      p_String
      p_Select
      p_Int
      p_Guid
      p_Date
      p_Choice
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage3" } } }) {
    items {
      p_String
      p_Select
      p_Int
      p_Guid
      p_Date
      p_Choice
    }
  }
}

Both versions return similar result structures. The primary difference is in how the where filter references content (by Name in CMS 12 versus _metadata.displayName in CMS 13).

Query referenced properties

CMS 13 changes how you query referenced content. In CMS 12, you expand referenced content through ContentArea, ContentAreaItem, ContentReference, LinkItem, LinkItemCollection, and similar properties. In CMS 13, you query referenced content only through ContentArea or ContentAreaItem. Other property types such as ContentReference, PageReference, and LinkItem return link information only.

ContentArea or ContentAreaItem properties

In CMS 12, ContentArea items are queried through ContentLink.Expanded, which returns the referenced data. CMS 13 removes this expansion model. Query referenced content explicitly through inline fragments or fragments instead.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    total
    items {
      MainContentArea {
        InlineBlock {
          ContentType
        }
        DisplayOption
        ContentLink {
          GuidValue
          Id
          ProviderName
          Url
          WorkId
          Expanded {
            ... on ButtonBlock {
              Name
              Created
              Url
              ButtonText
            }
          }
        }
      }
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    total
    items {
      MainContentArea {
        ... on ButtonBlock {
          _metadata {
            key
            locale
            fallbackForLocale
            version
            displayName
            published
            status
            changeset
            created
            lastModified
            sortOrder
            variation
            types
            url {
              type
              default
              hierarchical
              internal
              graph
              base
            }
          }
          ButtonText
        }
      }
    }
  }
}

The following query retrieves a ContentArea with multiple block types through inline fragments:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage2" } } }) {
    total
    items {
      MainContentArea {
        ... on ButtonBlock {
          _metadata {
            version
            created
            key
          }
          ButtonText
        }
        ... on EditorialBlock {
          _metadata {
            displayName
            key
          }
          _id
        }
        ... on TeaserBlock {
          _metadata {
            displayName
            key
          }
          Text
        }
      }
    }
  }
}

The following query retrieves a ContentArea with multiple block types through named fragments:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage2" } } }) {
    total
    items {
      MainContentArea {
        _metadata {
          displayName
          key
        }
        ...ButtonBlockFragment
        ...EditorialBlockFragment
        ...TeaserBlockFragment
      }
    }
  }
}

fragment ButtonBlockFragment on ButtonBlock {
  _metadata {
    version
  }
  ButtonText
}

fragment EditorialBlockFragment on EditorialBlock {
  _id
}

fragment TeaserBlockFragment on TeaserBlock {
  Text
}

Recursive queries on ContentArea

In CMS 12, the @recursive directive applies to ContentArea.ContentLink.Expanded with a default maximum depth of three levels. CMS 13 removes the Expanded field and applies recursion directly to the ContentArea property through the @recursive directive, typically inside a fragment. This approach provides cleaner queries and more reliable access to nested or cyclic ContentArea structures.

CMS 12 recursive query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    items {
      ContentArea {
        ContentLink {
          Expanded {
            Name
            ...ContentAreaBlock
          }
        }
      }
    }
  }
}

fragment ContentAreaBlock on ContentAreaBlock {
  Name
  ContentType
  ContentArea {
    ContentLink {
      Expanded @recursive(depth: 10) {
        Name
        ContentType
      }
    }
  }
}

CMS 13 recursive query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    items {
      MainContentArea {
        _metadata {
          displayName
        }
        ...ContentAreaBlock
      }
    }
  }
}

fragment ContentAreaBlock on ContentAreaBlock {
  _metadata {
    displayName
    types
  }
  cultureContentArea @recursive(depth: 10) {
    _metadata {
      displayName
    }
  }
}

ContentReference and ContentReferenceList properties

In CMS 12, ContentReference and ContentReferenceList properties expand and return the referenced content through the Expanded field. In CMS 13, these properties return a structured url object and a stable key. Query the referenced content explicitly when needed.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    total
    items {
      ContentReference {
        GuidValue
        Id
        Url
        WorkId
        Expanded {
          Url
          ContentLink {
            Id
            GuidValue
            Url
            WorkId
          }
        }
      }
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    total
    items {
      ContentReference {
        url {
          type
          default
          hierarchical
          internal
          graph
          base
        }
        key
      }
    }
  }
}

In CMS 13, ContentReference and ContentReferenceList properties reference content from external sources and CMS-managed content. Retrieve external items through the ContentReference.item field for unified querying of internal and external content.

External content reference query example:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    total
    items {
      ContentReference {
        url {
          type
          default
          hierarchical
          internal
          graph
          base
        }
        key
        item {
          _id
          ... on GraphShadowType {
            Name
            Id
            _id
            _modified
          }
        }
      }
    }
  }
}

External content reference result:

{
  "data": {
    "StandardPage": {
      "total": 1,
      "items": [
        {
          "ContentReference": {
            "url": {
              "type": "GRAPH",
              "default": null,
              "hierarchical": null,
              "internal": "cms://content/43fd8aecaad245d3b59b0db48c615cdb",
              "graph": "graph://shadow/GraphShadowType/101",
              "base": null
            },
            "key": "43fd8aecaad245d3b59b0db48c615cdb",
            "item": {
              "_id": "2",
              "Name": "Shakespeare",
              "Id": 101,
              "_modified": "2025-12-12T06:52:21Z"
            }
          }
        }
      ]
    }
  }
}

LinkItem, LinkItemList, and LinkItemCollection properties

In CMS 12, link data is retrieved through Href and ContentLink with expanded content details. CMS 13 simplifies the model by exposing a unified url object with structured URL types. The LinkItem, LinkItemList, and LinkItemCollection properties no longer expand referenced content.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    total
    items {
      LinkItem {
        Title
        Text
        Target
        Href
        ContentLink {
          Id
          WorkId
          GuidValue
          Url
          Expanded {
            Name
            Created
          }
        }
      }
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    total
    items {
      LinkItem {
        title
        text
        target
        url {
          type
          default
          hierarchical
          internal
          graph
          base
        }
      }
    }
  }
}

Url and UrlList properties

In CMS 12, Url and UrlList properties return plain string values. In CMS 13, these properties return structured objects with multiple representations. The Graph schema for Url includes the following fields:

  • default – The default URL for the content instance.
  • type – The type for the default value. Possible values include HIERARCHICAL, INTERNAL, EXTERNAL, and others.
  • hierarchical – The path for the content item based on the hierarchical structure in CMS 13.
  • internal – A permanent URL to the content item. The integration API uses this format to reference content items.
  • base – The authority for the content item. This value depends on the application configuration in CMS 13.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    total
    items {
      UrlToImage
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    total
    items {
      UrlToImage {
        type
        default
        hierarchical
        internal
        graph
        base
      }
    }
  }
}

XhtmlString and XhtmlStringList properties

In CMS 12, XhtmlString and XhtmlStringList properties return raw HTML as a plain string. CMS 13 returns rich text as a structured object that includes rendered HTML and a JSON representation. This structure enables more flexible rendering and content processing on the front end. The XhtmlString property returns the following fields by default:

  • html – The rendered HTML string.
  • json – A structured representation of the rich text.

The json value follows a tree structure:

  • The root node has type: "richText" and a children array.
  • Each child node has a type (for example, paragraph) and its own children.

CMS 12 query:

query MyQuery {
  StandardPage(where: { Name: { eq: "StandardPage1" } }) {
    items {
      XhtmlString
    }
  }
}

CMS 13 query:

query MyQuery {
  StandardPage(where: { _metadata: { displayName: { eq: "StandardPage1" } } }) {
    items {
      XhtmlString {
        html
        json
      }
    }
  }
}

CMS 12 result:

{
  "data": {
    "StandardPage": {
      "items": [
        {
          "XhtmlString": "<p>Apple is red!</p>"
        }
      ]
    }
  }
}

CMS 13 result:

{
  "data": {
    "StandardPage": {
      "items": [
        {
          "XhtmlString": {
            "html": "<p>Apple is red!</p>",
            "json": {
              "type": "richText",
              "children": [
                {
                  "type": "paragraph",
                  "children": [
                    {
                      "text": "Apple is red!"
                    }
                  ]
                }
              ]
            }
          }
        }
      ]
    }
  }
}

Experience query on CMS 13

Visual Builder in CMS 13 introduces a layout-and-composition-based approach to content creation that uses small, reusable content units. Use Experience queries to retrieve structured layout data for front-end rendering.

An Experience functions like a Page but supports layouts and unstructured editor-added content. Experiences organize content as an ordered list of Sections. Sections and Elements extend Blocks. Sections act as layout containers, while Elements represent the smallest content units and contain the actual content data. Elements are leaf nodes in the composition tree with no child elements.

The following query retrieves data for Experiences, Sections, and Elements. An Experience contains a composition field with a tree of nodes. CompositionStructureNode represents layout containers (Sections). CompositionComponentNode represents content units (Elements). Structure nodes contain other nodes, and component nodes are leaf nodes.

fragment _IComponent on _IComponent {
  __typename
  ... on BlankSection {
    longString
    string
    xhtmlString {
      html
    }
    Int
    contentArea {
      _metadata {
        key
        displayName
      }
      ... on _Content {
        _metadata {
          created
          version
        }
      }
    }
    contentReference {
      key
      url {
        default
        base
      }
    }
    block {
      Description
    }
  }
  ... on ContentAreaBlock {
    _metadata {
      displayName
      types
    }
    Link {
      Heading
      Text
    }
  }
}

fragment ElementFields on Element {
  Name
  Time
  Number
}

fragment _IExperience on _IExperience {
  composition {
    ...ICompositionNode
  }
}

fragment ICompositionNode on ICompositionNode {
  ... on CompositionStructureNode {
    key
    displayName
    nodeType
    layoutType
    component {
      ..._IComponent
    }
    nodes @recursive {
      type
      nodeType
      layoutType
      displayName
      key
      displayTemplateKey
    }
  }
  ... on CompositionComponentNode {
    key
    displayName
    nodeType
    component {
      ..._IComponent
      ...ElementFields
    }
  }
}

fragment BlankExperience on BlankExperience {
  ..._IExperience
}

query MyQuery {
  _Content(where: { _metadata: { displayName: { contains: "BlankExper236" } } }) {
    item {
      __typename
      _metadata {
        displayName
        version
      }
      ...BlankExperience
    }
  }
}

Variation query on CMS 13

CMS 13 lets editors create one or more variations of a page or an experience. A unique string in the variation field on the content metadata identifies each variation. By default, GraphQL queries return the original (non-variation) content only. Use the variation filter to query specific variations or retrieve all variations.

The following query retrieves all variations of a content item:

query GetAllVariations {
  _Content(variation: { include: ALL, includeOriginal: true }) {
    items {
      _metadata {
        key
        displayName
      }
    }
  }
}

The following query retrieves specific variations:

query variation {
  _Content(
    where: { _metadata: { displayName: { eq: "Rainrain" } } }
    variation: { includeOriginal: false, include: SOME, value: "Variation_2" }
  ) {
    items {
      _metadata {
        variation
        displayName
      }
    }
  }
}

The following query retrieves default content only (no variations):

query GetOnlyDefaultContent {
  _Content(variation: { include: NONE, includeOriginal: true }) {
    items {
      _metadata {
        displayName
        variation
      }
    }
  }
}

Optimizely Graph features

Core Content Graph features such as _children, _link, full-text search, filtering through search providers, and fuzzy search remain functionally consistent between CMS 12 and CMS 13. CMS 13 retains these capabilities and introduces a more normalized and composable schema. Update your query structure, not your feature logic.

Summary of key differences

CMS 13 introduces structural improvements through Optimizely Graph and the Experience model that change how you query content compared to CMS 12. The following list summarizes the key differences:

  • URLs return as structured objects instead of plain strings.
  • XhtmlString exposes both HTML and JSON representations by default.
  • ContentArea, ContentAreaItem, ContentReference, and Link properties no longer support Expand. Query referenced content explicitly.
  • All blocks are queryable through the unified _Component interface.
  • Queries use _Content and _Media as root fields instead of Content and individual media types.
  • CMS 13 adds support for _metadata, Experiences, external sources, and Variations.