dot CMS

How to fetch related content in dotCMS

How to fetch related content in dotCMS

Share this article on:

Understanding how to retrieve related content after defining your relationships can be complex. With several methods available, choosing the most optimal one can be a challenge.

You're likely curious about which option is the best for you! While there isn't a single, one-size-fits-all answer, the ideal choice truly depends on your unique use case. In this article, we will explore the most commonly used methods and showcase the scenarios where each shines the brightest.

Consider a scenario where you have a Blog that is related to one or more Authors. The content types might look like this:

Content Type

Fields

Blog

title, author (relationship field to Author)

Author

firstName, lastName, blog (relationship field to Blog)

 

And let's assume that we have a Blog called "French Polynesia Everything You Need to Know", which is related to the author “John Smith”.

// Blog Content
{
  "title": "French Polynesia: Everything You Need to Know",
  "identifier": "2b100ac7-07b1-48c6-8270-dc01ff958c69",
  "author": {
    "identifier": "f851e34a-d128-408e-a75a-4fa1c33201b8",
    "firstName": "John",
    "lastName": "Smith"
  }
}
// Author Content
{
  "identifier": "f851e34a-d128-408e-a75a-4fa1c33201b8",
  "firstName": "John",
  "lastName": "Smith",
  "blog": {
    "title": "French Polynesia: Everything You Need to Know",
    "identifier": "2b100ac7-07b1-48c6-8270-dc01ff958c69"
  }
}

How can you get the related content from each side of the relationship? Let's explore the options.

Option 1: Using the GraphQL API

Getting the author (child) having the blog identifier (parent)

GET Request: http://{host}/api/v1/graphql

query AuthorByBlog {
  search( query:"+identifier:2b100ac7-07b1-48c6-8270-dc01ff958c69") {
    title,
    ... on Blog {
      author {
         firstName,
         lastName
      }
    }
  }
}

Result

{
   "data": {
       "search": [
           {
               "title": "French Polynesia Everything You Need to Know",
               "author": [
                   {
                       "firstName": "John",
                       "lastName": "Smith"
                   }
               ]
           }
       ]
   }
}

 

Getting the blog (parent) given the author identifier (child)

GET Request: http://{host}/api/v1/graphql

query BlogsByAuthor {

    BlogAuthorCollection(query: "+identifier:f851e34a-d128-408e-a75a-4fa1c33201b8") {
        firstName
        lastName
        ... on BlogAuthor{
            blog{
                title
            }
        }
    }
}

Result

{
    "data": {
        "BlogAuthorCollection": [
            {
                "firstName": "John",
                "lastName": "Smith",
                "blog": [
                    {
                        "title": "French Polynesia Everything You Need to Know"
                    },
                    //other blogs
                ]
            }
        ]
    }
}

Pros:

  • You can ask only for the fields you need, reducing payload size

  • Nested queries are easy (e.g., blog → author → related blogs)

  • Strong typing helps catch errors early

 

Cons:

 

🎯 Use GraphQL when:

  • You’re building headless frontends with React/Astro/Next.js/etc

  • You need complex nested related content in one request

  • You want better performance by reducing over-fetching

  • You want flexibility and predictable schemas


Option 2: Using the REST APIs

We have multiple ways to retrieve related content using the different dotCMS APIs, but in this case, we will focus on the Content API with the “depth” and “related” parameters.

 

Case I: When “Depth” is important

The “depth” parameter will be helpful when you want to retrieve the original piece of content plus its related content. For example, we will get the author having the blog identifier and specifying the `depth=1` parameter to get related content at the first level (up to 3 for nested relationships).

GET Request: http://{host}/api/v1/content/2b100ac7-07b1-48c6-8270-dc01ff958c69?depth=1

 

Result

{
    "entity": [
        {
            "__icon__": "contentIcon",
            "archived": false,
            "baseType": "CONTENT",
            "contentType": "BlogAuthor",
            "contentTypeIcon": "person",
            "creationDate": 1600352407112,
            "disabledWYSIWYG": [],
            "firstName": "John",
            "folder": "SYSTEM_FOLDER",
            "hasLiveVersion": true,
            "hasTitleImage": true,
            "host": "48190c8c-42c4-46af-8d1a-0cd5db894797",
            "hostName": "demo.dotcms.com",
            "identifier": "f851e34a-d128-408e-a75a-4fa1c33201b8",
            "inode": "da883772-bc17-4adb-9e04-b49ffaafc792",
            "languageId": 1,
            "lastName": "Smith",
            //many other fields
        }
    ],
    "errors": [],
    "i18nMessagesMap": {},
    "messages": [],
    "pagination": null,
    "permissions": []
}

 

Case II: When “Related” is important

This is the case when you want to filter the related content based on a condition. The output will be a bit less verbose than in the previous example, because the details of the original content will be retrieved as well, but filtering the related content by the given criteria. Let's get our blog given the author identifier and an additional condition.

POST Request: http://localhost:8082/api/v1/content/related

//Request Body

{
 "fieldVariable": "blog",
 "identifier": "f851e34a-d128-408e-a75a-4fa1c33201b8",
 "condition": "+title:*Polynesia*" —> to filter our blog only
}

Result

{
    "entity": [
        {
            "author": [
                {
                    "baseType": "CONTENT",
                    "contentType": "BlogAuthor",
                    "firstName": "John",
                    "identifier": "f851e34a-d128-408e-a75a-4fa1c33201b8",
                    "inode": "da883772-bc17-4adb-9e04-b49ffaafc792",
                    "lastName": "Smith",
                    //many other fields
                }
            ],
            "baseType": "CONTENT",
            "identifier": "2b100ac7-07b1-48c6-8270-dc01ff958c69",
            "inode": "4b337160-a5a3-42a7-b272-7b506603cb72",
            "languageId": 1,
            "live": true,
            "title": "French Polynesia Everything You Need to Know",
            "working": true
            //many other fields
        }
    ],
    "errors": [],
    "i18nMessagesMap": {},
    "messages": [],
    "pagination": null,
    "permissions": []
}

Pros:

  • Simple to use

  • Fast for single-content lookups (if you know the identifiers or want easy search queries)

  • You can get all the details of the original piece of content and related content in just one request

 

Cons:

  • Verbose responses because you will get more fields than needed

  • The queries are not as flexible as GraphQL

  • The depth parameter can be heavy and hit performance if not used wisely

 

🎯 Use Rest APIs when:

  • You want quick, simple REST requests.

  • You need to expose content to external systems not using GraphQL.

  • You need relationship resolution but not highly-custom nested queries.


Option 3: Velocity Tools

Case I: Pulling a piece of content and iterating over the related content

 

In this case, we are pulling the blog and iterating over the authors:

#foreach($blog in $dotcontent.pull("+contentType:Blog",3,"modDate desc"))
    <h3>$blog.title</h3>
    #set($authors = $!{blog.author})
    <h4>Author(s):</h4>
    <ul>
        #foreach($author in $authors)
        	<li>$author.firstName $author.lastName</li>
        #end
    </ul>
#end

 

Case II: Pulling related content only

In this case, we pull authors only and iterate over their fields:

#foreach($content in $dotcontent.pullRelated("blog.author","2b100ac7-07b1-48c6-8270-dc01ff958c69",false,10))
    <li>$content.firstName</li>
    <li>$content.lastName</li>
#end

For further details on how to use the velocity viewtool, you can visit the dotCMS documentation.

Pros:

  • Full power of dotCMS server-side logic

  • Best performance when rendering HTML inside dotCMS pages

  • Direct access to contentlet objects and context (user session, permissions, current page context)

 

Cons:

  • Not headless: Tied to dotCMS backend rendering

  • Requires template editing in the CMS

  • Harder to reuse outside the CMS environment

 

🎯 Use Velocity when:

  • You are rendering server-side HTML pages inside dotCMS

  • You want maximum control over related content lookups without exposing APIs

  • You are using Velocity Widgets, Containers, or Templates


Wrapping up

There isn't a “best” way to pull related content. It will always depend on your use cases and the resources you have. There are other ways to pull relationships, but we can cover them in another article. In the meantime, these questions can help you with the decision, but remember that there is no rule of thumb:

1. Where will the content be consumed?

  • Headless frontend (React/Next/Gatsby/mobile)? → GraphQL or ContentAPI

  • dotCMS-rendered site? → Velocity Tools

 

2. Do you need nested related content (e.g., blog → author → related blogs → tags)?

  • Yes → GraphQL or Velocity

  • No → ContentAPI is enough

 

3. Do you need to control exactly which fields come back (to avoid over-fetching)?

  • Yes → GraphQL

  • No → ContentAPI or Velocity

 

4. Does your team have experience with GraphQL or want a typed/introspective schema?

  • Yes → GraphQL

  • No → ContentAPI or Velocity

 

5. Are you building a long-term scalable API layer (vs. a single internal template)?

  • Long-term, flexible, scalable → GraphQL

  • Short-term or CMS-only → ContentAPI or Velocity

Recommended Reading
  • Driving Content Innovation: Our 2026 Roadmap
    3 Mar 26
    Innovation

    Driving Content Innovation: Our 2026 Roadmap

    Join VP of Product Freddy Montes for a walk through of the exciting things dotCMS is working on in 2026

    Freddy

    Freddy Montes

    VP of Prodcut

  • Content Style Editor: Visual Design Control Inside Your CMS
    20 Feb 26
    Content Management

    Content Style Editor: Visual Design Control Inside Your CMS

    Eliminate developer bottlenecks with the dotCMS Content Style Editor, empowering content teams to instantly customize component styling, improve content reuse, and accelerate publishing without code.

    Marc

    Marc Boutillette

    Outbound Product Manager

  • A UX-Driven Approach to Modernizing dotCMS
    15 Jan 26
    Product

    A UX-Driven Approach to Modernizing dotCMS

    Modernizing a CMS isn’t about fixing what’s broken, it’s about leading its evolution. In this post, we share how dotCMS is taking a UX-led approach to future-proof the platform, aligning usability, scalability, and long-term product strategy to support what’s next.

    Maria

    Maria Fernandez

    Product Manager (formerly Head of UX)

  • The Top 10 Enterprise Content Management Systems in 2026
    1 Jan 26
    Content Management

    The Top 10 Enterprise Content Management Systems in 2026

    Discover the top 10 enterprise content management platforms that can transform how your business manages and delivers digital content.

    Fatima

    Fatima Nasir Tareen

    Growth Marketing Specialist

Explore dotCMS for your organization

image

dotCMS Named a Major Player

In the IDC MarketScape: Worldwide AI-Enabled Headless CMS 2025 Vendor Assessment

image

Explore an interactive tour

See how dotCMS empowers technical and content teams at compliance-led organizations.

image

Schedule a custom demo

Schedule a custom demo with one of our experts and discover the capabilities of dotCMS for your business.