Issues, Labels & Project Boards
Issues as the Unit of Work
A GitHub Issue is the fundamental unit of tracked work. Issues serve multiple purposes depending on context:
- Bug reports — "The login button throws a 500 when the email contains a plus sign"
- Feature requests — "Add support for dark mode"
- Tasks — "Update dependencies to address CVE-2024-12345"
- Questions (though GitHub Discussions is better for this)
- Proposals — "RFC: migrate from REST to GraphQL"
Issues are numbered sequentially within a repository (#1, #2, #3...) and the number is permanent — a closed issue's number is never reused. This makes issue numbers stable references in commit messages, PRs, changelogs, and team conversations.
Creating and Formatting Issues
Click New issue in the Issues tab. The creation form has:
- Title — a concise, specific description of the problem or feature
- Body — markdown-formatted details
- Assignees — who is responsible for this issue
- Labels — categorization
- Projects — link to a project board
- Milestone — link to a version milestone
Writing Good Issue Bodies
A good issue body for a bug report answers these questions:
- What happened? — the observed behavior
- What was expected? — the correct behavior
- How to reproduce? — numbered steps to trigger the bug
- Environment — OS, browser, version numbers
- Additional context — screenshots, error messages, logs
Issue Templates
Issue templates pre-fill the issue body with a structured format, guiding reporters toward providing the information you need. Well-designed templates dramatically reduce the back-and-forth of asking "can you provide steps to reproduce?"
Creating Issue Templates
Create templates in .github/ISSUE_TEMPLATE/. Each .md file becomes a template option:
Example Bug Report Template
Create .github/ISSUE_TEMPLATE/bug_report.md:
Example Feature Request Template
Create .github/ISSUE_TEMPLATE/feature_request.md:
Using a YAML Configuration File
Create .github/ISSUE_TEMPLATE/config.yml to customize the template chooser:
Setting blank_issues_enabled: false forces all issues to use a template — no blank issues allowed. This maintains consistent issue quality.
Labels — Creating, Applying, and Conventions
Labels are colored tags applied to issues and PRs for categorization and filtering. GitHub creates a default set when you create a repository (bug, documentation, enhancement, good first issue, etc.) but you will almost certainly want to customize them.
Managing Labels
Go to Issues → Labels (or the Labels page directly at /labels). You can:
- Create new labels with custom names, descriptions, and colors
- Edit existing labels
- Delete labels
- Transfer labels between repositories (not built-in — requires scripting or a tool)
A Practical Label Taxonomy
Many teams use a multi-dimensional label taxonomy where labels fall into categories:
Type labels (what kind of work):
bug— something is brokenenhancement— new feature or improvementdocumentation— docs-only changerefactor— code improvement without behavior changesecurity— security-related
Status labels (where in the workflow):
needs-triage— newly filed, not yet reviewedneeds-investigation— requires more context before work can beginblocked— waiting on something externalin-progress— actively being worked onready-for-review— implementation complete, needs review
Priority labels (how urgent):
P0: critical— production is down or data loss is occurringP1: high— affects many users, needs fixing soonP2: medium— meaningful impact, normal priorityP3: low— nice to have, tackle when convenient
Area labels (which part of the system):
area: frontendarea: backendarea: databasearea: infrastructure
Community labels:
good first issue— suitable for first-time contributorshelp wanted— maintainers welcome external contributions
Color Conventions
Use consistent colors per category. For example:
- Red/pink shades for bugs and critical priorities
- Blue shades for type labels
- Yellow/orange for status labels
- Green for good first issues and positive states
Consistent colors let contributors scan the label list and immediately understand the system.
Applying Labels
Labels can be applied from the issue sidebar, from the issue list (select multiple issues and use the Labels dropdown), or via the API/CLI:
Milestones — Grouping Issues by Version
Milestones group issues and PRs by a shared delivery goal — typically a version number or a date. A milestone has:
- A title (e.g., "v2.5.0", "Q2 2024", "Launch")
- An optional description
- An optional due date
- A progress indicator showing the percentage of associated issues/PRs that are closed
Creating Milestones
Go to Issues → Milestones → New milestone. Set the title, description, and due date.
Using Milestones Effectively
- Assign every issue or PR that must be completed for a release to the corresponding milestone.
- The milestone's progress bar gives you an at-a-glance view of release readiness.
- If the due date passes with open issues, the milestone turns red — an automatic signal that the timeline is at risk.
- Issues you decide to postpone to the next release can be moved to the next milestone rather than closed.
Assignees and Mentions
Assignees
Any issue or PR can have one or more assignees — the people responsible for it. Assignees:
- Receive notifications for activity on the issue/PR
- Show up in filtered views (e.g., "Issues assigned to me")
- Signal ownership and accountability
Convention: a new issue starts unassigned. When someone picks it up, they assign it to themselves. In project-managed teams, issues may be assigned during sprint planning.
Mentions
Mentioning a GitHub user (@username) or team (@org/team-name) in an issue, PR, or comment:
- Sends them a notification
- Creates a link to their profile
- Creates a "mentioned in" reference visible on their profile
Use mentions to pull in specific people when you need their attention: "cc @alice — this is in your area" or "@org/security-team can you review this for potential implications?"
GitHub Projects (v2)
GitHub Projects (v2, launched 2022) is a flexible project management tool built into GitHub. Unlike the original Projects, it provides:
- Multiple view types: Board, Table, and Roadmap
- Custom fields with rich types (date, iteration, single-select, number, text)
- Automation workflows
- Cross-repository views (a single project can contain issues from multiple repositories)
- Insights (built-in charts)
Creating a Project
- Go to your organization or user profile.
- Click Projects → New project.
- Choose a template (Table, Board, Roadmap, Backlog) or start blank.
- Give it a name.
Board View
The Board view shows issues as cards in columns. Columns can represent workflow states: Backlog, In Progress, In Review, Done.
Drag cards between columns to update their status. Each move can trigger an automation (e.g., moving to "In Progress" automatically sets the status field to in_progress).
Table View
The Table view shows issues as rows in a spreadsheet-like interface. You can:
- Sort by any column
- Filter by field values
- Group by field (e.g., group by Assignee, Priority, or Milestone)
- Show/hide columns
- Bulk-edit field values
Roadmap View
The Roadmap view renders issues on a timeline using start and end date fields. This view requires date fields — create them as custom fields or use iteration fields.
Custom Fields
Projects support custom fields for tracking data beyond what GitHub issues natively support:
- Text — freeform text notes
- Number — story points, hours, or any numeric value
- Date — start dates, target dates
- Single select — a dropdown with predefined options (great for Priority, Size, Status)
- Iteration — sprint-style fixed-duration cycles
Add custom fields from the project's Settings → Custom fields → New field.
Adding Items to a Project
Items can be added to a project in several ways:
- Manually: from the project, click + Add item and search for issues or PRs
- From an issue/PR sidebar: in the issue's right sidebar, click Projects and select the project
- Via automation: configure workflows to auto-add issues when they are created or labeled
Automating Project Cards with Workflows
Projects support automation rules that move items or update fields based on events.
Navigate to the project → Settings → Workflows. Built-in automation options include:
- Item added to project → set Status to a specified value
- Item reopened → set Status to "In Progress"
- Item closed → set Status to "Done"
- Pull request merged → set Status to "Done"
- Auto-add to project → automatically add new issues from a repository to the project when they match label criteria
Example: Auto-Triage Setup
Linking Issues to PRs
Linking issues to PRs creates a traceable connection between work tracked and work done. Two types of links:
Closing Links (Auto-Close on Merge)
Using closing keywords in a PR description closes the linked issue when the PR merges into the default branch:
Multiple issues: Closes #42, fixes #43
Cross-repository: Closes owner/repo#42
Reference Links (Without Closing)
Simply mentioning an issue number creates a reference link:
This shows "mentioned in [PR title]" on the issue, creating a hyperlinked trail without closing the issue.
Issue Closing Keywords in Commit Messages
Closing keywords work in commit messages too, not just PR descriptions. When a commit lands on the default branch (directly or via a squash merge), issues referenced with closing keywords are automatically closed.
This is particularly relevant for squash-and-merge workflows where a single squashed commit lands on main — that commit's message should include the Fixes #N line for the issue to auto-close.
GitHub Discussions vs Issues
GitHub Discussions is a forum-style communication tool built into GitHub repositories. It is separate from Issues and serves different use cases.
When to Use Issues
- Actionable, trackable work items
- Bug reports that require investigation and a fix
- Feature requests with a defined scope
- Tasks that can be assigned, labeled, and closed when done
Issues are designed to be closed — they represent a state of incompleteness that resolves.
When to Use Discussions
- Open-ended questions: "What's the best way to handle auth in this project?"
- Ideas that aren't ready to become issues: "I've been thinking about a plugin system..."
- Community Q&A: "How do I configure X for my use case?"
- Show and tell: "I built a project using this library — want to share!"
- General announcements
Discussions have categories, upvoting, and the ability to mark an answer as the accepted answer (turning a discussion into a resolved Q&A).
Enabling Discussions
Settings → General → check Discussions in the Features section.
The Practical Distinction
A useful heuristic: if a team member would add it to a sprint or assign it to someone, it's an issue. If it's a conversation that might produce an issue later, it's a discussion. Many projects explicitly document this in their CONTRIBUTING.md.
Practical Exercises
Exercise 1 — Set Up Issue Templates
- Create
.github/ISSUE_TEMPLATE/bug_report.mdandfeature_request.mdin a repository. - Add
config.ymlto disable blank issues. - Try creating a new issue and observe the template chooser.
- Fill out and submit a bug report using the template.
Exercise 2 — Build a Label Taxonomy
- Delete the default labels in a practice repository.
- Create a consistent set of labels using the taxonomy in this lesson: type labels, status labels, priority labels, and at least two area labels.
- Apply appropriate labels to three issues you create.
Exercise 3 — Set Up a Milestone and Assign Issues
- Create a milestone called "v1.0.0" with a due date one month from now.
- Create five issues representing features or bugs for your v1.0.0 release.
- Assign all five issues to the milestone.
- Close two of the issues and observe the milestone progress bar.
Exercise 4 — GitHub Projects Board
- Create a new GitHub Project.
- Add a Board view with columns: Backlog, In Progress, In Review, Done.
- Add a Table view with a custom Priority field (single-select: P0, P1, P2, P3).
- Add 5-10 issues from your repository.
- Set priorities on each, move them across columns.
- Set up an automation workflow that moves issues to "Done" when they are closed.
Exercise 5 — Link an Issue to a PR
- Create an issue: "Add a greeting message to the homepage."
- Create a branch and implement the feature.
- Open a PR with "Closes #N" in the description.
- Merge the PR.
- Verify that the issue was automatically closed and shows "closed by [PR]."