Skip to content

GitHub Discussions vs Issues: Choosing the Right Surface

Lesson 7 of 10Beginner10 min readGitHub Engineering · GitHub FundamentalsVerified: gh 2.98.0 (gh discussion is a preview command), August 2026

Discussions are threaded conversations attached to a repository or an organisation. They have categories, they support question-and-answer threads with an accepted answer, and — the defining property — they have no closed state to reach.

That absence is the whole design. An Issue is work, and work finishes. A Discussion is a conversation, and conversations simply end when people stop talking.

IssuesDiscussions
PurposeTrack workHold conversation
LifecycleOpen → closedOngoing
Success looks likeClosedAnswered, or simply useful
StructureFlat commentsThreaded replies
OrganisationLabels, milestones, assigneesCategories
Best answerNo such conceptAnswer can be marked accepted
Links to codeClosing keywords, commits, pull requestsReference only
AssignableYesNo
Appears in the work queueYesNo
Enabled by defaultYesNo — opt in

The row that decides most cases is the third. If you cannot describe what “done” means, you are not tracking work.

Different framings suit different people, and any of them works:

  • Closability. Can someone legitimately close this? → Issue. No? → Discussion.
  • Queue membership. Should this appear in a list of outstanding work? → Issue.
  • Audience. Is this for maintainers to act on, or for the community to talk about?
SituationSurfaceWhy
“Crashes on reconnect with a 4KB payload”IssueReproducible; closes when fixed
“How do I configure TLS with a custom CA?”Discussion (Q&A)A question; closes when answered, not when fixed
“Should we adopt semantic versioning?”DiscussionA decision to reach, not work to do
“Add retry support to the client”IssueShips, then closes
“Show us what you built with this”DiscussionNever finishes, by design
“v3 roadmap”DiscussionThen Issues for each item
“Docs for the auth flow are wrong”IssueFixable
“The API feels awkward for streaming”Discussion firstBecomes an Issue once a change is agreed

The last row is the most common healthy pattern: conversation until there is a concrete change, then an Issue for the change. Skipping the conversation produces Issues nobody can act on; skipping the Issue produces agreement nobody implements.

Discussions are organised into categories, and each category has a format that changes how threads behave:

  • Open-ended discussion — ordinary threaded conversation.
  • Question / Answer — replies can be marked as the accepted answer, and threads display as answered or unanswered.
  • Announcement — only maintainers can create threads; anyone can reply.
  • Poll — a question with options and voting.

The Q&A format is the one that changes behaviour most. An unanswered-question filter turns a Discussions space into something with a genuine work signal — not “issues to fix”, but “people waiting for a reply”. For any project with users, that queue matters more than it first appears: an unanswered question is a person deciding whether to keep using your software.

Announcement categories are worth setting up early. Without one, release notes and breaking-change warnings land in the same undifferentiated stream as everything else.

A workable starter set for a public project is small:

CategoryFormatFor
AnnouncementsAnnouncementReleases, deprecations, breaking changes
Q&AQuestion / AnswerUsage questions
IdeasOpen-endedFeature discussion before it becomes an Issue
Show and tellOpen-endedWhat people built

Four categories that people use beat twelve that they guess between.

Discussions are opt-in. Enable them only if someone will read them — an unmonitored Discussions tab where questions go unanswered for months is worse than no Discussions tab, because it advertises a support channel that does not exist.

Terminal window
gh repo edit owner/repo --enable-discussions

Once enabled, three things are worth doing immediately:

  1. Replace the default categories with a small set that matches your project.
  2. Add a link from your Issue template chooser so questions are routed to Discussions before being filed as Issues. This is far more effective than converting them afterwards.
  3. Write a pinned post explaining where things belong. One paragraph. People do read the pinned post when the space is small.

The relationship works in both directions, and both are useful.

Issue → Discussion. For questions filed in the wrong place. The conversion keeps the content and its comments, and notifies the author. This is the polite alternative to closing something as “wrong place” — nothing is lost and the person gets an answer.

Discussion → Issue. For a conversation that has produced a concrete piece of work. Create the Issue from the Discussion so the reasoning is linked; the Discussion stays as the record of why, and the Issue tracks the what.

Discussions are the most public-facing surface a repository has, and unlike Issues they attract people who are not filing bug reports. A few tools matter:

  • Pinning keeps orientation posts visible.
  • Locking stops replies on a thread that has run its course.
  • Marking as answered in Q&A categories resolves the thread’s state.
  • Reporting and blocking for abuse.
  • Transferring a Discussion to another repository when it belongs elsewhere.

A repository’s CODE_OF_CONDUCT.md is worth having before you need it. Moderating against a written standard is straightforward; moderating without one turns every decision into a personal judgement that someone will contest.

Discussions are a GraphQL-first feature. Unlike Issues, there is no full-featured REST surface — which is itself a useful thing to know, because reaching for gh api repos/OWNER/REPO/discussions does not work the way the equivalent Issues call does.

Terminal window
gh api graphql -f query='
query($owner: String!, $repo: String!) {
repository(owner: $owner, name: $repo) {
discussions(first: 10, orderBy: {field: UPDATED_AT, direction: DESC}) {
nodes {
number
title
isAnswered
category { name }
}
}
}
}' -F owner=OWNER -F repo=REPO

The isAnswered field is the one worth building on: a scheduled query for unanswered questions older than a few days is a genuinely useful piece of project hygiene, and it is a handful of lines.

The CLI also has a gh discussion command, but note its status:

The GraphQL API lesson covers the query language properly, including pagination through connections, which you will need for any repository with more than a page of threads.

When nobody will monitor them. An unanswered support channel damages a project’s reputation more than not having one.

For anything with a deadline. No assignees, no milestones, no queue. If it must be done by Friday, it is an Issue.

For security reports. Never. Vulnerabilities go through a private channel — a security policy with a private reporting route. A Discussion is a public disclosure.

As a substitute for documentation. An answer buried in a thread is not documentation. If the same question is asked three times, the answer belongs in the docs, and the third answer should be a link.

When your community is elsewhere. If your users already talk in a chat platform, a second half-empty forum helps nobody. Discussions work when they are where the conversation actually is.

Running a Discussions space that stays useful

Section titled “Running a Discussions space that stays useful”

Enabling Discussions is easy; keeping them worth reading takes a small amount of ongoing work.

Answer questions, or say you cannot. An unanswered question in a Q&A category is a person deciding whether to keep using your software. “I do not know, but here is where to look” is a real answer and takes a minute.

Mark answers. The accepted-answer mechanism is what makes the Q&A category more than a forum. It also produces the unanswered filter, which is your work queue — and without marking, that filter is noise.

Promote answers into documentation. The third time a question is asked, the answer belongs in the docs and the third reply should be a link. A Discussions space that substitutes for documentation grows without bound, and every answer is discoverable only by full-text search.

Prune categories that are not used. A category with two threads in eight months is telling you something. Fewer, busier categories work better than a taxonomy nobody fits into.

Pin an orientation post. One paragraph explaining what belongs where. People do read it when the space is small, and it prevents the drift that is expensive to correct later.

The most effective use of Discussions is not as a destination but as a filter in front of the Issue tracker.

Configured well, the flow looks like this:

Someone has a problem
Issue template chooser
┌────┴────┐
↓ ↓
Bug report "Question? → Discussions"
↓ ↓
Issue Discussion (Q&A)
answered, or becomes an Issue

The routing happens in .github/ISSUE_TEMPLATE/config.yml:

blank_issues_enabled: false
contact_links:
- name: Question or usage help
url: https://github.com/OWNER/REPO/discussions/categories/q-a
about: Ask here — questions are answered faster in Discussions.
- name: Report a security vulnerability
url: https://github.com/OWNER/REPO/security/policy
about: Please do not file security issues publicly.

blank_issues_enabled: false is the load-bearing line. Without it, the chooser is advisory and anyone can bypass it with a blank Issue — which is what most people do.

The security link matters independently. A vulnerability filed as a public Issue is a public disclosure, and the moment to prevent that is before it is filed.

Worth being honest about, because “enable Discussions” is often suggested as free.

They need monitoring. An unmonitored space is an advertised support channel that does not respond, which damages a project more than having none.

They fragment the record. With Issues, Discussions and documentation, the answer to a question can be in three places. Consolidating is work.

They accumulate. Threads never close, so the space grows monotonically. Search is the only navigation past a few hundred, and search is only as good as the titles people wrote.

They can substitute for documentation. The most common failure: a well-answered Discussions space where the answers were never promoted, so every new user re-asks.

For a project with an active community and someone willing to tend the space, they are clearly worth it. For a small project where the maintainer already struggles with the Issue tracker, adding a second inbox usually makes things worse rather than better.

Enabling Discussions and not reading them. The single most damaging option.

Twelve categories on a project with thirty users. People guess, guess wrong, and stop caring.

Using Issues for questions because Discussions were never enabled. The tracker fills with things that cannot close.

Never marking answers. Q&A without accepted answers is just threads, and the unanswered filter becomes meaningless.

Letting a decision live only in a Discussion. If it produced a change, it needs an Issue; if it produced a rule, it needs documentation.

Automating against gh discussion while it is in preview. Its interface can change under you.

  1. Enable Discussions on your practice repository with gh repo edit --enable-discussions.
  2. Reduce the categories to three or four that would suit a real project.
  3. Post a question in the Q&A category, answer it yourself, and mark the answer as accepted.
  4. Open an Issue that is really a question, then convert it to a Discussion and note that the comments survive.
  5. Run the GraphQL query above and confirm isAnswered reflects step 3.

Step 5 matters more than it looks: it is the first time in this pillar that you read GitHub state through GraphQL rather than through a page, and the shape of that response is what the API cluster builds on.

  • Discussions have no closed state, which is exactly why they suit conversation and not work.
  • The decision rule is closability: if nobody can legitimately close it, it is not an Issue.
  • Category format changes behaviour — Q&A adds accepted answers and an answered/unanswered signal.
  • Converting between Issues and Discussions preserves content and is kinder than closing.
  • Discussions are GraphQL-first; the REST surface is not equivalent to the Issues one.
  • gh discussion is currently a preview command and is a weak foundation for durable automation.

If you enable Discussions and do nothing else, do these three things. They take ten minutes and prevent most of the ways the space goes wrong.

Reduce the categories to three or four. Write one pinned post saying what belongs where. And add a link from the Issue template chooser routing questions to the Q&A category before they become Issues.

That last one does the most work, because it fixes the problem at intake rather than requiring anyone to move things afterwards.

Free Git Engineer Cheat Sheet BundleSix printable references plus downloadable toolkit files — commands, recovery, aliases, a CODEOWNERS starter. No email required.