Skip to main content

Zenhub Epics vs Legacy Epics

⚠️ DEPRECATION NOTICE

This documentation describes Zenhub epics and legacy epics which have been removed from the Zenhub platform as part of the sub-issues migration in June 2025. It's kept for reference purposes only and the functionality will be removed in the coming months.

ℹ️ UPDATED DOCUMENTATION

Epics and Projects have been replaced with Issue Types and Sub-Issues. For current documentation, see:

Zenhub previously supported two types of epics: Legacy Epics and Zenhub Epics. Legacy Epics were based on GitHub Issues, while Zenhub Epics were exclusive to the Zenhub application and did not require a GitHub account for users.

An organization could not have both types of epics simultaneously. Legacy Epics were only available to organizations that were created before May 30, 2022, and hadn't yet been migrated to Zenhub Epics.

Due to structural differences, these two types of epics had different resources in the GraphQL API. The GraphQL type for Legacy Epics was Epic, while the type for Zenhub Epics was ZenhubEpic. If your organization was not enabled for a particular type of epic, queries or mutations on that type would return empty or result in errors.

Migration to Issue Types

The functionality of Epics and Projects is now available through Issue Types with hierarchical levels:

  • Level 1: Initiatives (highest strategic level)
  • Level 2: Epics (large features or capabilities)
  • Level 3: Stories (user-facing requirements)
  • Level 4: Tasks (implementation work)
  • Level 5: Sub-tasks (granular work items)

To migrate your existing workflows:

  1. Create appropriate issue types using the Issue Types guide
  2. Convert existing epics/projects to issues with appropriate issue types
  3. Use sub-issues to maintain hierarchical relationships (Sub-Issues guide)
  4. Update your team processes to use the new issue type system

Checking the Epic Type Used by Your Organization

To determine whether your organization used Zenhub or Legacy Epics, you could open your board and check the sidebar for an "Epics" link. If the "Epics" link was present, your organization was using Zenhub Epics. Otherwise, your organization was using Legacy Epics.

Zenhub sidebar with Epics link

Legacy Epics were marked as deprecated in the GraphQL API. However, if your organization was enabled for Legacy Epics, you had to use the deprecated resources.

How to Get Your Workspace ID

Some queries in this guide required a workspace ID. You can find your workspace ID in the URL of your workspace. For example, in the URL https://app.zenhub.com/workspaces/-demo-board-58e6e818b2c8573a4fa86b6b, the workspace ID is 58e6e818b2c8573a4fa86b6b.

For more information, see the Getting Entity IDs guide.

Legacy API Reference (Deprecated)

The following sections contain the legacy API documentation for reference purposes only. Do not use these APIs for new implementations.

Zenhub Epics Queries and Mutations (Deprecated)

Create a Zenhub Epic

Use the createZenhubEpic mutation to create a Zenhub Epic:

mutation createZenhubEpic($zenhubRepositoryId: ID!, $zenhubOrganizationId: ID!, $title: String!, $body: String) {
createZenhubEpic(input: {
zenhubRepositoryId: $zenhubRepositoryId,
zenhubOrganizationId: $zenhubOrganizationId,
zenhubEpic:{
title: $title,
body: $body
}
}) {
zenhubEpic {
id
}
}
}

Note: The zenhubRepositoryId argument was optional at the moment, but it was required starting on October 1st, 2023, so it was highly recommended that you start sending it. See Article for more details.

You could obtain the Zenhub Repository ID and the Zenhub Organization ID from your workspace with the following query:

query zenhubRepositoryandOrganization($workspaceId: ID!) {
workspace(id: $workspaceId) {
zenhubRepository {
id
}
zenhubOrganization {
id
}
}
}

List All Zenhub Epics of a Workspace

To list all Zenhub Epics of a workspace, use the following query:

query zenhubEpicsFromWorkspace($workspaceId: ID!) {
workspace(id: $workspaceId) {
zenhubEpics {
nodes {
id
title
}
}
}
}

This query required a workspace ID. You could obtain your workspace ID by following the instructions in How to Get Your Workspace ID.

This query could also be used to retrieve the ID of a specific epic by its title. To do so, pass the query argument:

query zenhubEpicsFromWorkspace($workspaceId: ID!, $query: String) {
workspace(id: $workspaceId) {
zenhubEpics(query: $query) {
nodes {
id
title
}
}
}
}

Get Zenhub Epic by ID

You could retrieve a Zenhub Epic by its ID using the node query:

query zenhubEpicById($zenhubEpicId: ID!) {
node(id: $zenhubEpicId) {
... on ZenhubEpic {
title
}
}
}

Update a Zenhub Epic

To update a Zenhub Epic, use the following mutation. Obtain your Zenhub Epic ID using the query described in List All Zenhub Epics of a workspace.

mutation updateZenhubEpic($zenhubEpicId: ID!, $title: String, $body:String) {
updateZenhubEpic(input:{
zenhubEpicId: $zenhubEpicId,
title: $title,
body:$body
}) {
zenhubEpic {
title
}
}
}

Get All Issues from a Zenhub Epic

The issues belonging to a Zenhub Epic could be retrieved using the childIssues field of the ZenhubEpic:

query zenhubEpicIssues($zenhubEpicId: ID!, $workspaceId: ID!) {
node(id: $zenhubEpicId) {
... on ZenhubEpic {
childIssues(workspaceId: $workspaceId) {
nodes {
id
title
}
}
}
}
}

You could obtain your Zenhub Epic ID using the query described in List All Zenhub Epics of a Workspace, and your workspace ID by following the instructions in How to Get Your workspace ID.

Add Issues to Zenhub Epics

To add issues to Zenhub Epics, use the following mutation:

mutation addIssuesToZenhubEpic($epicIds: [ID!]!, $issueIds: [ID!]!) {
addIssuesToZenhubEpics(input: {
zenhubEpicIds: $epicIds,
issueIds: $issueIds
}) {
zenhubEpics {
id
}
}
}

Remove Issues from Zenhub Epics

To remove issues from Zenhub Epics, use the following mutation:

mutation removeIssuesFromZenhubEpics($epicIds: [ID!]!, $issueIds: [ID!]!) {
removeIssuesFromZenhubEpics(input: {
zenhubEpicIds: $epicIds,
issueIds: $issueIds
}) {
zenhubEpics {
id
}
}
}

Update Zenhub Epic Dates

To change Zenhub Epic dates, use the following mutation:

mutation updateZenhubEpicDates($zenhubEpicId: ID!, $startOn: ISO8601Date!, $endOn: ISO8601Date!) {
updateZenhubEpicDates(input: {
zenhubEpicId: $zenhubEpicId,
startOn:$startOn,
endOn: $endOn,
}) {
zenhubEpic {
id
startOn
endOn
}
}
}

Legacy Epics Queries and Mutations (Deprecated)

Create a Legacy Epic

The createEpic mutation was used to create a Legacy Epic:

mutation createEpic($repositoryId: ID!, $title: String!, $body: String) {
createEpic(input: {
issue: {
repositoryId: $repositoryId,
title: $title,
body: $body,
}
}) {
epic {
id
}
}
}

You could obtain the repository ID by checking the connected repositories in your workspace with the query:

query repositoryIds($workspaceId: ID!) {
workspace(id: $workspaceId) {
repositoriesConnection {
nodes {
name
id
}
}
}
}

This query required a workspace ID. You could obtain your workspace ID by following the instructions in How to Get Your Workspace ID.

List All Legacy Epics of a Workspace

To list all legacy epics of a workspace, use the following query:

query epicsFromWorkspace($workspaceId: ID!) {
workspace(id: $workspaceId) {
epics {
nodes {
id
issue {
title
}
}
}
}
}

This query could also be used when you wanted to know the ID of a specific epic by its title. To do that, you could pass the query argument:

query epicsFromWorkspace($workspaceId: ID!, $query: String!) {
workspace(id: $workspaceId) {
epics(query: $query) {
nodes {
id
issue {
title
}
}
}
}
}

Get Legacy Epic by ID

You could get a Legacy Epic by its ID using the node query:

query epicById($epicId: ID!) {
node(id: $epicId) {
... on Epic {
issue {
title
}
}
}
}

Update a Legacy Epic

To update a Legacy Epic, you needed to update its inner issue. First, get the issue ID using the Get Legacy Epic By ID query. Then, use the updateIssue mutation to update the epic:

mutation updateEpic($issueId: ID!, $title: String!, $body: String) {
updateIssue(input: {
issueId: $issueId,
title:$title,
body: $body
}) {
issue {
id
}
}
}

Get All Issues From a Legacy Epic

The issues belonging to a Legacy Epic could be retrieved using the childIssues field of the Epic:

query epicIssues($epicId: ID!) {
node(id: $epicId) {
... on Epic {
childIssues {
nodes {
id
title
}
}
}
}
}

Add Issues to Legacy Epics

To add issues to Legacy Epics, use the following mutation:

mutation addIssuesToEpic($epicIds: [ID!]!, $issueIds: [ID!]!) {
addIssuesToEpics(input: {
epicIds: $epicIds,
issueIds: $issueIds
}) {
epics {
id
}
}
}

Remove issues from Legacy Epics

To remove issues from Legacy Epics, use the following mutation:

mutation removeIssuesFromEpic($epicIds: [ID!]!, $issueIds: [ID!]!) {
removeIssuesFromEpics(input: {
epicIds: $epicIds,
issueIds: $issueIds
}) {
epics {
id
}
}
}

Update Legacy Epic dates

To change Legacy Epic dates, use the following mutation:

mutation updateEpicDates($epicId: ID!, $startOn: ISO8601Date!, $endOn: ISO8601Date!) {
updateEpicDates(input: {
epicId: $epicId,
startOn:$startOn,
endOn: $endOn,
}) {
epic {
id
startOn
endOn
}
}
}