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:
- Issue Types - Creating and managing Epic, Project, and Initiative issue types
- Sub-Issues - Hierarchical relationships for breaking down work
- Working with Issues - Using issue types when creating strategic work items
- Working with Issues and Issue Types - Complete overview
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:
- Create appropriate issue types using the Issue Types guide
- Convert existing epics/projects to issues with appropriate issue types
- Use sub-issues to maintain hierarchical relationships (Sub-Issues guide)
- 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.

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
}
}
}