---
canonical: https://amplience.com/developers/docs/workforce/flows/installing-extensions-with-graphql/
title: Workforce extensions
description: Learn how to install extensions with the GraphQL Asset Management API
audience: Developer
image: https://cdn.media.amplience.net/i/ampproduct/content-flow-hello-world-action-extension-1?w=1200&h=630
image_width: 1200
image_height: 630
date_published: 2025-11-19
date_modified: 2026-04-07
---

# Installing extensions with GraphQL

On this page we explain how to install an extension using the [GraphQL Management API](https://amplience.com/developers/docs/apis/asset-management/overview/) using the example of the Hello World extension. The GraphQL examples in this section can be run from the [GraphQL playground](https://api.amplience.net/graphql) or your own code.

Here are the steps to install the Hello World extension.

## Step 1- Find the hub id

To install an extension on a hub, you first need to find the hub id. Use the following query to list your hubs and find the one you want. The hub id will be passed in the `cmsHubId` in the following steps.

```graphql
query listHubs {
  viewer {
    organizations {
      edges {
        node {
          id
          name
          cmsHubs {
            id
            name
          }
        }
      }
    }
  }
}
```

#### Example response

We will install the Hello World extension on the "docsconductor" hub with the id `Q01TSHViOm9yZ19GZEN5cFdLN0I3SE9FZlJNLzY4OWQwN2YyNGUxMWU2NjZiOWZmNWZhNg==`.

```json
{
  "data": {
    "viewer": {
      "organizations": {
        "edges": [
          {
            "node": {
              "id": "T3JnYW5pemF0aW9uOm9yZ19GZEN5cFdLN0I3SE9FZlJN",
              "name": "conductor",
              "cmsHubs": [
                {
                  "id": "Q01TSHViOm9yZ19GZEN5cFdLN0I3SE9FZlJNLzY4OWQwN2YyNGUxMWU2NjZiOWZmNWZhNg==",
                  "name": "docsconductor"
                }
              ]
            }
          }
        ]
      }
    }
  }
}
```

### Step 2: Create the extension

Creating an extension builds a wrapper for it, containing metadata such as its label and icon. Use the `createExtension` mutation to create the extension.

- `cmsHubId` is the id of the hub on which you want to install the extension. Find the hub id by running the query shown in Step 1.

- The label will be used as the folder name in the Action Library in Workforce. Your actions will be shown within this folder.

- The description is markdown format text that will be used to provide detailed information about the extension.

- The url should usually be a link to docs providing more information.

- The extension icon is shown in the Action Library in Workforce. It must be specified as an SVG, either as a URL or inline as a Base64 encoded string. In the example below, the SVG is included inline.

```graphql
mutation createExtension {
  createExtension(
    input: {
      cmsHubId: "Q01TSHViOm9yZ19GZEN5cFdLN0I3SE9FZlJNLzY4OWQwN2YyNGUxMWU2NjZiOWZmNWZhNg=="
      label: "Hello world"
      description: "A simple extension that takes a name string from the user and outputs the name appended to hello world"
      url: "https://amplience.com/developers/docs"
      icon: "data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTI4IiBoZWlnaHQ9IjEyOCIgdmlld0JveD0iMCAwIDEyOCAxMjgiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CjxwYXRoIGQ9Ik0xMTEuNDY3IDExNC4yMzVMMzQuNzkyOCAxMTQuMzMxTDM0LjcxMDkgNDkuMDI1M0w2MC4wNzQzIDIyLjM4NzNMMTExLjM1MiAyMi4zMjNMMTExLjM2MiAzMC40MDg0TDExMS40NTMgMTAzLjAwMkwxMTEuNDY3IDExNC4yMzVaIiBzdHJva2U9IiMyMTYwODMiIHN0cm9rZS13aWR0aD0iMiIvPgo8cGF0aCBkPSJNODEuMjA0IDIyLjM2MDhMNjAuMDc0NSAyMi4zODczTDM0LjcxMTEgNDkuMDI1M0wzNC43ODg4IDExMS4wNTFMMjMuMjg4MiAxMTMuNzYzTDguMTY0MDYgNDkuNjM5N0wyNi45Mzk0IDE3LjYzMzdMNzcuMjg4MiA1Ljc1ODU0TDgxLjIwNCAyMi4zNjA4WiIgc3Ryb2tlPSIjMjE2MDgzIiBzdHJva2Utd2lkdGg9IjIiLz4KPHBhdGggZD0iTTI2LjUzNjkgMTguMjE0NEwzMi44NDE0IDQ0LjA2MjhMOC4xNjc5NyA1MC4wODA3IiBzdHJva2U9IiMyMTYwODMiIHN0cm9rZS13aWR0aD0iMiIvPgo8cGF0aCBkPSJNNjAuMDc0MyAyMi4zODcyTDYwLjEwNzcgNDguOTkzNEwzNC43MTA5IDQ5LjAyNTMiIHN0cm9rZT0iIzIxNjA4MyIgc3Ryb2tlLXdpZHRoPSIyIi8+CjxwYXRoIGQ9Ik00NS41IDgxLjMzMTVIMTAwLjgzMyIgc3Ryb2tlPSIjRjg4QjhCIiBzdHJva2Utd2lkdGg9IjIiLz4KPHBhdGggZD0iTTQ1LjUgNzAuNjY0OEgxMDAuODMzIiBzdHJva2U9IiNGODhCOEIiIHN0cm9rZS13aWR0aD0iMiIvPgo8cGF0aCBkPSJNNDUuNSA5MS4zMzE1SDEwMC44MzMiIHN0cm9rZT0iI0Y4OEI4QiIgc3Ryb2tlLXdpZHRoPSIyIi8+CjxwYXRoIGQ9Ik00NS4xNTIzIDEwMi4xMjdIMTAwLjYiIHN0cm9rZT0iI0Y4OEI4QiIgc3Ryb2tlLXdpZHRoPSIyIi8+Cjwvc3ZnPg=="
    }
  ) {
    id
    label
  }
}
```

#### Example response:

The extension id and label will be returned. You will need the extension id to create the extension release in the next step.

```json
{
  "data": {
    "createExtension": {
      "id": "RXh0ZW5zaW9uOjA5MDI0YThmLWQ2MGUtNDQzNy1iMTRiLWY2ZjZkMzYzNzViYw==",
      "label": "Hello world"
    }
  }
}
```

### Step 3: Create the extension release

A release contains a specific version of the extension, including its code and the manifest file. The code and manifest both need to be specified as escaped JSON strings. There can be multiple versions of an extension installed on the same hub (and the user can choose between them).

You will need to include:

- The extension id
- The label. This will generally be the version
- An escaped version of the manifest file. In the Hello World example, this is generated in the dist folder as part of the build.
- The code to your index.js. This also needs to be escaped. In the example query below, triple quotes are used to escape the entire code block.
- Draft is set to true so that it is only visible on your account.

```graphql
mutation createExtensionRelease {
  createExtensionRelease(
    input: {
      extensionId: "RXh0ZW5zaW9uOjA5MDI0YThmLWQ2MGUtNDQzNy1iMTRiLWY2ZjZkMzYzNzViYw=="
      label: "0.0.1"
      draft: true
      latest: false
      sourceFiles: [
        {
          path: "manifest.json"
          content: "{\"envSchema\":{\"type\":\"object\",\"properties\":{\"HELLO_DEFAULT_NAME\":{\"type\":\"string\",\"title\":\"Default name when name input is empty\"}}},\"actions\":[{\"name\":\"hello\",\"label\":\"Hello\",\"description\":\"Say hello\",\"inputSchema\":{\"type\":\"object\",\"properties\":{\"name\":{\"type\":\"string\"}}},\"outputSchema\":{\"type\":\"object\",\"properties\":{\"message\":{\"type\":\"string\"}}}}]}"
        }
        {
          path: "index.js"
          content: """
          // src/actions/hello.ts
          function hello({ name }) {
            const messageName = name || process.env.HELLO_DEFAULT_NAME;
            return { message: messageName ? `Hello ${messageName}` : `Hello world` };
          }
          export {
            hello
          };
          """
        }
      ]
    }
  ) {
    id
    label
  }
}
```

#### Example response

This extension release id is returned. You will need this to create the extension instance.

```json
{
  "data": {
    "createExtensionRelease": {
      "id": "RXh0ZW5zaW9uUmVsZWFzZTo1Y2ZjYTNmNy1hM2FhLTQ5ZjgtOTQzYy1kOGM5ODcyYjJhMGM=",
      "label": "0.0.1"
    }
  }
}
```

### Step 4: Create an extension instance

Creating an extension instance will install the extension on your hub. You need to specify:

- `cmsHubId`. Use the same hub id you used in previous steps.
- `extensionId`. This is the id returned by the `createExtension` mutation.
- `extensionReleaseId`. This is returned by `createExtensionRelease`. You can install multiple releases of the same extension on a hub. The user will be offered a choice of which extension to use.
- `label` and `description`. Details of this instance.
- `env`. Include this in the input if you have environment variables (such as an API key). In the Hello world example, a `HELLO_DEFAULT_NAME` property is defined in the environment variable section of the manifest. It will be used as the default name if no name is passed to the Hello action.

```graphql
mutation createExtensionInstance {
  createExtensionInstance(
    input: {
      cmsHubId: "Q01TSHViOm9yZ19GZEN5cFdLN0I3SE9FZlJNLzY4OWQwN2YyNGUxMWU2NjZiOWZmNWZhNg=="
      extensionId: "RXh0ZW5zaW9uOjA5MDI0YThmLWQ2MGUtNDQzNy1iMTRiLWY2ZjZkMzYzNzViYw=="
      extensionReleaseId: "RXh0ZW5zaW9uUmVsZWFzZTo1Y2ZjYTNmNy1hM2FhLTQ5ZjgtOTQzYy1kOGM5ODcyYjJhMGM="
      label: "Hello World - 0.0.1 - ev default"
      description: "Hello World Extension"
      env: { HELLO_DEFAULT_NAME: "Mr EV default" }
    }
  ) {
    id
    label
  }
}
```

#### Example response

The extension instance id and label will be returned in the response. You can delete an extension instance with the `deleteExtensionInstance` mutation, passing the instance id.

```json
{
  "data": {
    "createExtensionInstance": {
      "id": "RXh0ZW5zaW9uSW5zdGFuY2U6ZDQ0NmNhNzEtM2U4NC00NzIyLThlNDQtNmQxZmIxNWZjNWY5",
      "label": "Hello World - 0.0.1 - ev default"
    }
  }
}
```

### Step 5: List the extension instances on your hub

You check that the extension instance has been installed on your hub by running the following query. A list of extension instances will be returned, together with the extensions.

```graphql
query listExtensionInstances {
  cmsHub(
    id: "Q01TSHViOm9yZ19GZEN5cFdLN0I3SE9FZlJNLzY4OWQwN2YyNGUxMWU2NjZiOWZmNWZhNg=="
  ) {
    extensionInstances {
      id
      label
    }
    extensions {
      edges {
        node {
          id
          description
        }
      }
    }
  }
}
```

#### Example response

The instance of the Hello world extension is shown in the response.

```json
{
  "data": {
    "cmsHub": {
      "extensionInstances": [
        {
          "id": "RXh0ZW5zaW9uSW5zdGFuY2U6ZDQ0NmNhNzEtM2U4NC00NzIyLThlNDQtNmQxZmIxNWZjNWY5",
          "label": "Hello World - 0.0.1 - ev default"
        }
      ],
      "extensions": {
        "edges": [
          {
            "node": {
              "id": "RXh0ZW5zaW9uOjA5MDI0YThmLWQ2MGUtNDQzNy1iMTRiLWY2ZjZkMzYzNzViYw==",
              "description": "A simple extension that takes a name string from the user and outputs the name appended to hello world"
            }
          }
        ]
      }
    }
  }
}
```

## Testing the extension

Once installed on the hub, the extension is now shown in the Action Library under a category called "Hello World".

The name of the action is specified in the manifest file, while the folder label is configured when the extension is created using the `createExtension` mutation.

![The Hello action is now available in the Action Library](https://cdn.media.amplience.net/i/ampproduct/content-flow-hello-world-action-extension-1?w=1880&fmt=png 'The Hello action is now available in the Action Library')

## Download the Hello world example

You can [download](https://amp-product.s3.eu-west-1.amazonaws.com/extensions-examples/hello-world-extension.zip) the Hello world example, including the code and manifest.
