Auto-Close Sub-Issues When Parent Issue Is Closed
GitHub introduced sub-issues at the beginning of 2025, allowing users to break down large issues into smaller, more manageable tasks. This hierarchy makes it easier to track progress and organize work, especially for complex projects.
I worked on projects that adopted this feature early, but found it repetitive and easy to miss manually closing each sub-issue once the parent issue was completed. To solve this problem, I automated the process and created Auto-Close Sub-Issues custom action. Now, when a parent issue is closed, a GitHub Actions workflow automatically closes all of its open sub-issues and posts a summary comment for visibility.
Why Auto-Close Sub-Issues?
The benefits are simple:
- Save time — no need to manually close each sub-issue when the parent is done.
- Avoid mistakes — sub-issues won’t get accidentally left open after the parent is resolved.
- Keep your tracker accurate — open means open, closed means closed.
- Clean audit trail — sub-issues are closed with
state_reason: completedfor a cleaner issue timeline.
How It Works
The action listens to the issues.closed event and does the following:
- Fetches all sub-issues of the closed parent using GitHub’s Sub-Issues API, with pagination to handle any number of sub-issues.
- Filters to only open sub-issues — already-closed ones are left untouched.
- Closes each open sub-issue concurrently in chunks, setting
state_reason: completed. - Posts a summary comment on the parent issue listing what was closed — and flags any failures.
- Exposes
closed_countandtotal_countas outputs for downstream steps.
Auto Close Sub-Issues in action
Getting Started
Add a workflow file at .github/workflows/close-sub-issues.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
name: Close Sub-Issues
on:
issues:
types: [closed]
permissions:
issues: write
contents: read
jobs:
close-sub-issues:
runs-on: ubuntu-latest
steps:
- name: Close Sub-Issues
uses: RehabAbotalep/auto-close-sub-issues@v1
with:
github_token: $
issue_number: $
repository: $
That’s it. No extra secrets, no configuration needed.
The
permissionsblock is required. Withoutissues: write, the action will fail with a403 - Resource not accessible by integrationerror.
Configuration Options
| Input | Description | Required |
|---|---|---|
github_token | GitHub token for authentication | Yes |
issue_number | The issue number of the parent issue | Yes |
repository | The repository in owner/repo format | Yes |
| Output | Description |
|---|---|
closed_count | Number of sub-issues successfully closed |
total_count | Total number of sub-issues found (including already-closed ones) |
What the Comment Looks Like
When the action runs successfully, it posts to the parent issue:
On success:
1
âś… Automatically closed the following sub-issues: #12 #13 #14
On partial failure:
1
2
3
âś… Automatically closed the following sub-issues: #12 #13
⚠️ Failed to close 1 sub-issue(s): #14
If all closures fail:
1
⚠️ Failed to close all sub-issue(s): #12 #13 #14
Under the hood
A few implementation decisions worth noting:
- Pagination — the action uses
per_page: 100and loops until all pages are exhausted, so it handles repos with many sub-issues without silently dropping any. - Chunked concurrency — sub-issues are closed in parallel batches of 10 to keep throughput high without hammering the API rate limit.
- Partial failure handling — a single failed closure doesn’t abort the rest; every sub-issue is attempted independently and failures are reported in aggregate.
state_reason: completed— sub-issues are closed with an explicit reason rather than the defaultnull, which produces a cleaner audit trail in the issue timeline.
A notable limitation
One thing worth calling out: GitHub Actions requires a runner for every job, even lightweight ones that only make API calls.
In Azure DevOps, we often use agentless jobs (pool: server) to handle orchestration tasks — like approvals or REST API calls — without consuming compute resources. GitHub Actions doesn’t currently support this, which means even simple API operations like this one spin up a runner and consume workflow minutes.
I’ve raised a feature request with GitHub to support agentless jobs for these scenarios: GitHub Community Discussion #159471.
Try It Out
The action is available on the GitHub Marketplace. The full source is on GitHub.
Give it a try, open an issue if you run into anything, or submit a PR — contributions are welcome.