Creating a headless content definition

November 14, 2023
Note: This tutorial assumes you already have a Jahia installation up and running. If you don't, we suggest you follow the First steps with Jahia tutorial to get a local install of Jahia that runs in a Docker image.

In this tutorial, you will learn how to build a new content definition that you can use in a headless project. A content definition is a declaration that defines the structure (made of simple properties or child objects) of a content object. A content object is a small structured piece of content that you add to a page for display in a browser or mobile device. A content definition is stored in a CND file. A CND file is a text file that contains content definitions using a standardized syntax. For more details, see Node Type Notation on the Apache Jackrabbit site.

After deploying a content definition in Jahia, you can use the Jahia authoring interface to create, update, and delete content objects using the definition. After creating content objects, you can use the GraphQL API to manipulate the content through a remote headless application such as a Progressive Web Application or a native mobile application.

In this tutorial, you will create a content definition for an “experience” content object that can display on a mobile device and contains image, title, and text properties.

In this tutorial you:

  • Create a content definition in Jahia Studio
    In Jahia Studio, you create a new module that contains the content definition. A module is a package that you deploy to extend or modify Jahia. Then you use the definition builder tool to define title, text, and image properties for the definition.
  • Create a new web project and deploy the module in the project
    You compile the module and then create a web project and deploy the module in the project. In Content and Media Manager, you create a new content object and specify a title, text, and image for the object. Finally, you publish the content object.
  • Access content through the headless GraphQL API
    You use the SDL Generator tool to map GraphQL fields to the properties in the content definition. Then you execute GraphQL queries against the content object.

Creating the content definition in the Jahia Studio

Next you create a content definition that contains a title, text, and image property. Using Jahia Studio, you can build content definitions using the definition builder tool to create CND files instead of writing them by hand. Once you master the syntax, you can of course decide to work directly with CND files. The finished definition looks like this.


In this section you create a new content object, add base attributes to the type, specify a name, and then add a text and an image property.

Note: You can only access Studio from a Jahia Cloud development environment.

To create the content object:

  1. Access Jahia using the following URL: http://localhost:8080. Log in using root and root credentials. The My Web Projects page displays.
  2. Click the menu in the upper-left corner to open the Jahia menu and click Studio.
  3. In Jahia Studio, create a new module by selecting New>New module in the top toolbar.
  4. In the Create module dialog, leave the module type as module and enter headless-definitions for the module name. Click OK. Leave other parameters as default.

    Jahia downloads dependencies from the network and generates a new module. This typically takes a few minutes if you created a module in another tutorial or otherwise up to 20 minutes.
  5. Select the File system tab
    in the left navigation pane and navigate to headless-definitions/src/main/resources/META-INF/definitions.cnd.
  6. Right-click on the definitions.cnd file and select New node type namespace. Enter mynt as the prefix and as the URI. The URI doesn’t really need to exist. It is just a unique identifier that ensures there is no conflict between namespaces. Click Save.
    Your file should now look like this:
  7. Click Save. It is a good idea to do regularly save your work, especially if your network connection is unreliable.
  8. Select the definitions.cnd file again, right-click and select the New node type definition.
  9. In the dialog, you must select a Mixin node type or a Primary node type. Mixin node types are types that can extend an existing type (it’s a form of polymorphism), while Primary node types are the base type of a content definition. Select Primary nodetype and click OK.

You are now ready to start defining your node type.

To define attributes and properties for the node type:

  1. In the Add: Primary nodetype dialog, in Type name, in the first drop down, select mynt as a prefix, and then type experience as the type name. The type name must be unique and is used later when you query for content.
    Note: In this tutorial, you do need to provide a title for the node type. Titles are used in the resource bundles.
  2. In Mixins, add jmix:droppableContent and jmix:editorialContent to the right column to make the definition available to users in Edit mode and Content and Media Manager in Jahia. The jmix:droppableContent mixin allows users to drag-and-drop the node type in Edit mode. The jmix:editorialContent mixin specifies the category in which it is available.
    Your Title and Mixins section of the page should now look like this:

Next you add the name, text, and image properties for the content definition.

To add the name property:

  1. Select the Properties tab and click Add. In the Name dialog, enter name as the item name and click OK.
  2. Select the new property under Name.
  3. Select the Internationalized checkbox to specify that the property can contain a separate value for each language in the site.
  4. Select the Mandatory checkbox to make the property required. 

To add the text property:

  1. Add a new property called text and click OK.
  2. Select the text property in Selector type select RichText to enable rich text editing in the text field for users.
  3. Select the Internationalized and Mandatory checkboxes.

To add the image property:

  1. Add a new property called images.
  2. Make sure the images property is selected and change the Required type to WeakReference.
    Note: For more information on property types, see Understanding content types.
  3. Change the Selector type to Picker.
  4. Click the Add button under Selector options and type the following text: type='image'.
  5. Select the Multiple checkbox to allow users to select more than one image in Edit mode.
  6. Select the Mandatory checkbox. 
  7. In Value constraints, click Add and type jmix:image to restrict linking only to existing images. jmix:image is the node type used by Jahia to represent images.
  8. Click Save. Your file should now look like this (you might need to refresh it by clicking on another file and clicking back on it):
    <jmix = ''>
    <jnt = ''>
    <mynt = ''>

    [mynt:experience] > jnt:content, jmix:droppableContent, jmix:editorialContent
    - name (string) mandatory internationalized
    - text (string, richtext) mandatory internationalized
    - images (weakreference, picker[type='image']) mandatory multiple < 'jmix:image'

You have created the node type. As you can see, the definition builder makes it easy for you to get started quickly. You don’t have to know (at this point) what all the various options do to build powerful and flexible content definitions.

Deploying and publishing the new module

You are now ready to compile and deploy your new module. After deploying the module, you create a content object from the content definition in Content and Media Manager. Then you publish the content object to make it available to users. The content object renders like this in the content editor.


To deploy and publish the new module:

  1. Select the File system tab
    in the left navigation pane and click the Compile and deploy module button
    . The module compiles and is deployed.
  2. In the top toolbar, select Mode>Administration to open the Administration page in Jahia.
  3. Click Web Projects and click the Create button at the top of the page.
  4. On the Create your Web Project page, enter Headless site as a name and headless-site as a site key.
  5. Leave the other fields as they are and click Next.
  6. In Choose modules to be deployed, add the headless-definitions module to the Selected modules column. Your page should look like this:
  7. Click Next and then click Save on the confirmation page.
  8. Click the Jahia logo at the top left and click Content and Media Manager. Content and Media Manager loads.
Note: Content and Media Manager is a module that provides a single interface for editors to create and organize content and files. For more information, see Using and customizing Content and Media Manager.

To specify settings in Content and Media Manager:

  1. In Content and Media Manager, click the Create button and select New content.
  2. Open the base folder, select experience and click OK.
  3. The content editor page opens and displays an interface with the name, text, and image properties that you specified in your content definition earlier. Enter a sample name and description as content.
  4. To add images:
    1. Click in the images field dots to open Images page.
    2. Click the Upload button
      and then the Browse button to upload an image from your computer. You can add multiple images one at a time by clicking Browse after selecting an image. Then click OK to upload the images.
    3. Your images now appear in the main window. Select the images you want and click Save. The content editor page should now look something like this:
  5. Click Save. You have now created your first content element in Content and Media Manager. Next you publish the content to make it available on your public site.
  6. Select your newly created experience node, right click and select Publish>Publish experience - English.
  7. The Publication dashboard page open. From here you can directly publish or start a publication workflow. In this case, you will directly publish so click the Publish button.

Congratulations, you have successfully created a site and a content element using your new headless content definition. In the next section, you will learn how to access this new content object through the headless GraphQL API.

Accessing content through the headless GraphQL API

In Jahia, there are two ways to access content through the GraphQL API:

  • A generic JCR node-based API that is very powerful but requires understanding the underlying JCR tree structure to access content
  • An SDL GraphQL API that makes it possible to map GraphQL fields to content definitions so that the GraphQL API will be very close to the definition structure. No understanding of the JCR node structure is needed.

For the purpose of this tutorial you will use the SDL GraphQL API approach. This will feel a lot more natural to front-end developers as well as any developers who work with GraphQL.

First you will create the SDL mapping using the SDL generator tool that is built into Jahia.

To create the SDL mapping:

  1. Connect to Support Tools using the following URL: http://localhost:8080/tools
  2. Enter your Jahia administrative username and password, which is jahia/password by default. The Support Tools page opens.
  3. In Modules, select SDL Generator Tools : sdlGeneratorTools.
  4. In the SDL Generator Tools page, click Add new type next to Node type.
  5. In the Add new type dialog, search for experience and leave the Custom property name default value and click Add.
  6. Click Add new property next to Property.
  7. Click on Select property.
  8. Select the name property and click Add.
  9. Click Add new property and select the text property and click Add.
  10. For the images you need to map the property to a type, so first click Add new property but this time select Select and map property to type.
  11. Select ImageAsset in the Predefined type dropdown.
  12. Select the images property in the Select a property dropdown.
  13. Leave the Custom property name default value as is. Ensure that As list is enabled. Click Add.
  14. On the right side in the GraphQL Schema panel you should have something that looks like this:
    type Experience @mapping(node: "mynt:experience") {
    metadata: Metadata
    name: String @mapping(property: "name")
    text: String @mapping(property: "text")
    images: [ImageAsset] @mapping(property: "images")

To make experiences searchable by property: 

  1. Click the Next button on the bottom right of the pane.
  2. Add a finder field by clicking on the Add a finder link next to the Finder title. This will make it possible to retrieve experiences by properties.
  3. In Select a finder, select the ...byName finder and type experiences in Custom name to generate a finder called experiencesByName. Click Add.
  4. Your schema should now look like this:
    type Experience @mapping(node: "mynt:experience") {
    metadata: Metadata
    name: String @mapping(property: "name")
    text: String @mapping(property: "text")
    images: [ImageAsset] @mapping(property: "images")

    extend type Query {
    experiencesByName: [Experience]
  5. Click Next and click Copy to clipboard.
  6. In a separate browser tab, open http://localhost:8080 and navigate back to Jahia Studio.
  7. In the drop down at the top left of the Studio, select the headless-definitions module, select the File system tab and navigate to the following directory:
  8. Right-click the META-INF directory and select New file. The code editor opens.
  9. Paste the content you copied previously from the SDL Generator tool and click Save.
  10. Enter graphql-extension.sdl as a file name. Do not change the file name. Click Submit.
  11. Click Compile and deploy module to deploy your changes.
  12. Open Support Tools again (http://localhost:8080/tools).
  13. In Modules, select Jahia GraphQL Core Provider : sdlreporttooll. Check that everything is green. If not, check the steps you have done as there might have been an error.
  14. Go back to the Support Tools and this time select Jahia GraphQL Core Provider : graphiql
  15. Click on Docs at the top right of the view. The Documentation Explorer opens.
  16. Click on the Query type
  17. You should see your experience GraphQL query fields now, as shown below:
  18. You can now use these fields to build a query. In the left pane, paste the following query:
    experiencesByName(contains:"Jahia") {
    images {

    Make sure you change the contains to include something you know is in the name you have entered previously when creating the content.
  19. Click the Execute button
  20. You should get a result that looks something like this:

If you want, don’t hesitate to change the query on the left panel, and you will see that auto-completion and the documentation browser make it very easy to figure out which fields are available to build a query. You can use the newly defined GraphQL types and fields in your next headless project!

Congratulations, you have completed this tutorial! Here’s a review of what you have learned. You have:

  • Created a new standard module using the Jahia Studio
  • Used Jahia Studio to create new content definitions using the Definition Builder tool
  • Deployed your new module
  • Used the new module to create a headless site
  • Used Content and Media Manager to create content that will be exposed through the GraphQL API
  • Used the SDL Generator tool to build a mapping from the JCR content definition to a GraphQL types and fields.
  • Used the SDL Report tool to check that the SDL mapping is properly deployed and functional
  • Use the embedded GraphiQL tool to browse the generated schema as well as build your first GraphQL query using the new types and fields and retrieved the content element that was created in the Content and Media Manager.

Note: If at any time you make a mistake and want to go back to the Studio to make modifications, ensure that you Compile and deploy your module after making changes. Jahia will use the updated version of your module.

Did you know?

You can build definitions and views simply by editing the files by hand. The tools here are intended to make it easy for you to get started. You can also edit your modules using your own preferred IDE as they are Maven projects under the hood.

Where to go from here?

To learn more about using content types and Content and Media Manager from a user perspective:

To learn more about GraphQL:

To learn about managing content definitions: