GitHub Issues and Projects — The 'Fix' Issue That Sat for 6 Months
A critical security issue was filed but never triaged.
20+ years shipping production infrastructure and CI/CD at scale. Notes here come from systems that actually shipped.
- ✓GitHub account, basic understanding of Git and GitHub repositories, familiarity with Markdown, command-line basics for running scripts (optional).
Open an issue: gh issue create --title 'Bug' --body 'Description'. Create a Project Board: GitHub → Projects → New Project. Automate: use issue templates, labels, and project workflows.
GitHub Issues is like a communal to-do list for your codebase. Anyone can add a card ('the login button is broken'), assign it to someone, label it ('bug', 'urgent'), and discuss the fix. GitHub Projects is a bulletin board where you move these cards through columns: 'To Do' → 'In Progress' → 'Done'. Together they turn chaos (random bug reports in Slack) into a structured workflow that the whole team can see.
| Chrome | Firefox | Safari | Edge |
|---|---|---|---|
| ✓ | ✓ | ✓ | ✓ |
Every team has a Slack channel where bugs get reported. And lost. GitHub Issues solves this by putting every bug, feature request, and task in a searchable, assignable, labeled database tied directly to the code. GitHub Projects adds prioritization and workflow tracking. The combination is powerful enough for many teams to replace Jira entirely. This guide covers issue templates, labels, project boards with automation, and the incident where a missing triage process led to a 6-month-old security issue becoming a production breach.
Why Track Work Beyond Code?
Git is great for code, but it's terrible for project management. Issues and pull requests don't tell you why a feature was built, who approved it, or whether it's blocked by a dependency. GitHub Issues and Projects fill that gap by providing a structured way to track tasks, bugs, and features alongside your codebase. Without them, teams rely on Slack messages, spreadsheets, or memory—each a recipe for chaos. In production, I've seen teams miss deadlines because a critical bug was discussed in a DM and never logged. GitHub Projects gives you a single source of truth for what's being worked on, why, and by whom. It's not optional; it's how you scale beyond a 2-person team.
Setting Up Issue Templates for Consistency
Issue templates are your first line of defense against ambiguity. They force reporters to provide structured information, making triage faster. GitHub supports both Markdown-based templates and YAML-based forms. I prefer YAML forms because they enforce required fields and dropdowns, reducing back-and-forth. For example, a bug report template should include environment details, steps to reproduce, expected vs actual behavior, and logs. In production, I've seen teams waste hours asking 'What version are you on?' because the template didn't require it. Set up templates in .github/ISSUE_TEMPLATE/ and configure them in the repository settings. You can also use config.yml to blank issues and link to a contact channel.
Organizing Work with Labels and Milestones
Labels and milestones are the scaffolding of your project management. Labels categorize issues by type (bug, enhancement), priority (critical, low), or status (needs review, blocked). Milestones group issues toward a specific goal, like a release or sprint. In production, I've seen teams use too many labels (50+) and then ignore them. Stick to a small set: bug, feature, tech-debt, blocked, needs-triage, and priority: critical. Milestones should have a clear due date and description. Use the GitHub API to enforce that issues in a milestone must have a specific label. This prevents 'zombie milestones' that never close.
GitHub Projects: Kanban Boards That Sync with Issues
GitHub Projects (the new Projects experience) is a kanban board that syncs with issues and pull requests. Unlike the old Projects, the new version is built on a spreadsheet-like table with custom fields, views, and automation. You can create a board with columns like 'To Do', 'In Progress', 'In Review', and 'Done'. Each card is an issue or PR. The killer feature is automation: when a PR is merged, you can automatically move the linked issue to 'Done'. In production, I've seen teams manually drag cards and forget to update status. Automate everything. Use the 'Item added to project' trigger to set default fields like 'Status: To Do'.
Linking Issues to Pull Requests for Traceability
When a PR closes an issue, GitHub automatically links them and moves the issue to 'Done' if configured. This creates an audit trail: you can see exactly which code change resolved which issue. Use keywords like closes #123, fixes #123, or resolves #123 in the PR description. In production, I've seen teams forget to link issues, leading to orphaned PRs that nobody understands. Enforce linking with a branch naming convention (e.g., feature/123-add-login) and a PR template that asks 'Which issue does this close?'. Use GitHub Actions to block PRs without an issue reference.
Using Custom Fields for Priority, Effort, and Sprint
GitHub Projects' custom fields let you add metadata like priority (High, Medium, Low), effort (story points), sprint iteration, or target release. These fields power views and filters. For example, you can create a view that shows only 'High priority' items in the current sprint. In production, I've seen teams use labels for priority, but labels are messy for sorting. Custom fields are typed (text, number, date, single select) and can be used in automation. Use a 'Sprint' field with a date range to track iterations. Combine with a 'Points' field for velocity tracking. Export the project data to a CSV for reporting.
Automating Workflows with GitHub Actions and Project Automation
GitHub Actions can automate almost any project management task: auto-assign issues, add labels based on content, move cards between columns, or send Slack notifications. For example, when a PR is merged, you can automatically close the linked issue and move it to 'Done'. Or when an issue is opened with 'bug' label, auto-assign it to the on-call engineer. In production, I've seen teams manually assign issues and forget to update status. Automate everything that's deterministic. Use the actions/add-to-project action to add issues to a project board. Use actions/github-script for custom logic.
Reporting and Insights: Measuring Team Velocity
GitHub Projects doesn't have built-in velocity charts, but you can export data and use external tools. Use the GraphQL API to fetch items with custom fields like 'Points' and 'Sprint'. Then calculate velocity as total points completed per sprint. In production, I've seen teams guess velocity and consistently miss commitments. Track actual vs planned points over 3-4 sprints to get a reliable number. Use a simple script to generate a burndown chart. Also track cycle time (time from issue opened to closed) to identify bottlenecks. Share these metrics in a weekly team dashboard.
Best Practices for Scaling Across Teams
When multiple teams share a repository, use issue templates with team-specific fields, labels per team (e.g., team:platform), and project boards per team or per initiative. Use the 'Iteration' field for sprints and 'Team' custom field for ownership. In production, I've seen cross-team issues fall through cracks because nobody owned them. Use a shared 'Triage' board where unassigned issues live until a team picks them up. Also, use GitHub's 'Organization Projects' to create cross-repo boards for company-wide initiatives. Enforce a policy that every issue must have a team label and a priority.
Common Pitfalls and How to Avoid Them
Pitfall 1: Over-customization. Too many fields, labels, and workflows confuse the team. Start minimal and iterate. Pitfall 2: Ignoring the board. If the board doesn't reflect reality, people stop using it. Automate status updates and enforce discipline. Pitfall 3: Using issues for everything. Not every conversation needs an issue. Use discussions for open-ended questions. Pitfall 4: No cleanup. Close stale issues after 90 days of inactivity. Use a GitHub Action to auto-close issues with a 'stale' label. In production, I've seen backlogs with thousands of open issues, most of which are irrelevant. Regular grooming is essential.
The Security Issue That Sat in the Backlog for 6 Months
- Every issue needs a triage process: labels, project board, assignee rotation.
- Security issues need a separate triage pipeline with SLA.
- Use issue templates with required fields.
- Automate labeling and project board placement.
| File | Command / Code | Purpose |
|---|---|---|
| .github | name: Bug Report | Why Track Work Beyond Code? |
| .github | blank_issues_enabled: false | Setting Up Issue Templates for Consistency |
| label-milestone-check.sh | MILESTONE="v1.0" | Organizing Work with Labels and Milestones |
| .github | name: Project Automation | GitHub Projects |
| .github | name: Require Issue Link | Linking Issues to Pull Requests for Traceability |
| export-project.js | const { graphql } = require('@octokit/graphql'); | Using Custom Fields for Priority, Effort, and Sprint |
| .github | name: Auto Assign Bug | Automating Workflows with GitHub Actions and Project Automat |
| velocity.py | query = """ | Reporting and Insights |
| .github | name: Feature Request | Best Practices for Scaling Across Teams |
| .github | name: Close Stale Issues | Common Pitfalls and How to Avoid Them |
Key takeaways
Frequently Asked Questions
20+ years shipping production infrastructure and CI/CD at scale. Notes here come from systems that actually shipped.
That's Git. Mark it forged?
4 min read · try the examples if you haven't