How to Write Effective GitHub Issue Templates
A pull request template improves the quality of proposed changes, but it only helps after someone has already made it to the solution stage. GitHub issue forms solve the earlier problem: they shape the information you collect when someone reports a bug, asks for an enhancement, or suggests a documentation fix. In that sense, they're the natural companion to a pull request template, and for many repositories they do even more to reduce maintainer back-and-forth.
While my previous post, How to Write an Effective GitHub Pull Request Template, was about improving review, this post is about improving intake.
- Pull request templates help contributors explain a proposed change.
- Issue template help contributors explain a problem, an idea, or a gap before any code has been written.
That distinction matters, because most maintainer time is lost much earlier in the process: missing reproduction steps, missing environment details, vague enhancement requests, and documentation issues with no concrete suggestion.
GitHub supports both legacy Markdown issue templates and the newer issue forms, but this post is specifically about issue forms. That's the model I use. They're YAML-based, support required fields, structured inputs, dropdowns, markdown instructions, uploads, and per-field validation. Most importantly, they let you ask only for the information that a specific type of issue actually needs.
Start With Three Forms¶
The files live in .github/ISSUE_TEMPLATE/ and are read from the default branch. In most repositories, I generally start with three forms:
| Form | Use Case |
|---|---|
bug.yml | Something is broken and needs to be reproduced and fixed. |
enhancement.yml | Something is missing and needs a clearer problem statement or use case. |
docs.yml | Something needs to be clarified, corrected, or expanded in the documentation. |
Those three cover the majority of contributor traffic cleanly.
That's the shape I come back to over and over. It's small enough to maintain, but broad enough to cover the kinds of issues most repositories actually receive.
I also pair those forms with a chooser configuration:
In this repository, the file is intentionally minimal: blank issues are disabled. That forces contributors to choose one of the defined forms instead of bypassing the structure entirely.
Note
I covered this file in detail in Configuring the GitHub Issue Template Chooser. If you want to add contact_links for Discussions, upstream documentation, or support resources, that post walks through the full config.yml schema.
The Shape of an Issue Form¶
A GitHub issue form isn't a large schema, but it helps to know where the moving parts actually are. These are the top-level keys I reach for most often.
| Key | What It Does | Example |
|---|---|---|
name | The display name shown in the issue template chooser. | name: Bug |
description | Short helper text shown under the template name in the chooser. | description: Report a bug or unexpected behavior in the library. |
title | Pre-populates the issue title field. | title: "[Bug]: " |
labels | Applies one or more labels automatically when the issue is created. | labels: ["bug"] or labels: ["bug", "triage"] |
assignees | Assigns one or more GitHub usernames automatically. | assignees: ["tenthirtyam"] |
projects | Adds the issue to one or more GitHub Projects. | projects: ["tenthirtyam/67"] |
type | Sets the issue type when your repository uses GitHub issue types. | type: bug |
body | Defines the actual form fields contributors will fill out. | body: |
Tip
Some practical notes on those keys:
nameanddescriptionare what contributors see first, so write them for humans, not for maintainers reading the YAML later.titleis helpful when you want a consistent prefix such as[Bug]:or[Docs]:, but leave enough room for contributors to summarize the issue clearly.labelsis one of the highest-value keys in the file. Applyingbug,enhancement,documentation, ortriageautomatically means new issues arrive pre-categorized.assigneesis best used when a repository has a very small maintainer group. In larger repositories, automatic assignment can create noise or bottlenecks. This key expects GitHub usernames, not team slugs.projectsis useful when your issue tracker and your planning workflow are tightly connected. If you don't actively use GitHub Projects, skip it.typeis useful, but only if you're already using GitHub's issue types consistently. If not, labels are usually the more portable way to categorize work.
For the keys that commonly take arrays, this is what single-value and multi-value usage looks like:
labels: ["bug", "triage"]
assignees: ["tenthirtyam", "octocat"]
projects: ["tenthirtyam/67", "tenthirtyam/88"]
The body key is where issue forms stop being metadata and start becoming a workflow. Each entry in body: is a field or instruction block. The field type determines what GitHub renders.
| Field Type | Use It For | Notes |
|---|---|---|
markdown | Instructions, search-before-filing reminders, links, and context. | Great for pointing to docs, existing issues, or your Code of Conduct. |
input | Short single-line values. | Good for versions, operating system releases, URLs, and usernames. |
textarea | Longer free-form responses. | Best for descriptions, reproduction steps, logs, code samples, and expected vs actual behavior. |
dropdown | Selecting from a controlled list of options. | Useful when you want clean, normalized input for OS, version families, or feature areas. |
checkboxes | One or more acknowledgments or multi-select choices. | Ideal for Code of Conduct agreement and contributor confirmations. |
upload | Attaching screenshots or other files. | Useful for UI bugs, diagrams, logs, and supporting artifacts. |
For most repositories, those six field types are enough.
The other two keys you'll use constantly inside body items are attributes and validations.
attributescontrols the field's visible behavior: the label, helper text, placeholder, available options, and rendering hint.validationscontrols whether GitHub requires the field before the issue can be submitted.
For example:
- type: textarea
id: error-output
attributes:
label: Error Output
description: Provide the complete error output or stack trace.
render: text
validations:
required: false
That split is worth understanding:
type: textareadefines the shape of the input.id: error-outputgives the field a stable internal identifier.attributesdefines how the field is presented to the contributor.validationsdefines whether GitHub will allow the form to be submitted without it.
Once you see that pattern, most of the schema becomes fairly intuitive.
Keep Simple Forms Simple¶
Not every issue type needs a long form. A common mistake is to treat every issue like a production outage and ask for far more information than the reporter can reasonably provide. That increases abandonment without improving the quality of the issue tracker.
For lighter-weight issue types, I prefer short forms with a small number of high-value fields.
Documentation Issues¶
Documentation issues are often even smaller. Sometimes the most useful report is simply: "this section is unclear" and "here is what I expected instead."
A compact form lowers the barrier to that kind of feedback.
Example:
---
name: Documentation
description: Found a typo or something that needs clarification?
labels:
- documentation
body:
- type: markdown
attributes:
value: >
When filing a documentation issue, please include the following information.
- type: textarea
id: motivation
attributes:
label: Motivation
description: Why should we update our docs or examples?
validations:
required: false
- type: textarea
id: suggestion
attributes:
label: Suggestion
description: What should we do instead?
validations:
required: false
Enhancement Requests¶
The enhancement form asks for three things: description, use cases, and references. That's enough structure to move the conversation from "I want a thing" to "here is the problem this would solve."
In practice, that's the pattern: the smaller and less urgent the issue type, the smaller the form should be.
Example:
---
name: Enhancement
description: Is something critical missing?
labels:
- enhancement
body:
- type: markdown
attributes:
value: >
When filing an enhancement request, please include the following information.
- type: textarea
id: description
attributes:
label: Description
description: Provide an overview of the enhancement.
validations:
required: true
- type: textarea
id: use-case
attributes:
label: Use Case(s)
description: Provide any relevant use-cases.
validations:
required: true
- type: textarea
id: references
attributes:
label: References
description: Provide any references.
validations:
required: false
Build the Bug Form Carefully¶
Bug reports are where structure pays off the most. A vague enhancement request can still turn into a useful conversation. A vague bug report usually turns into a stalled issue.
Example:
---
name: Bug
description: Is something not working as expected?
labels:
- bug
body:
- type: markdown
attributes:
value: >
When filing a bug report, please include the following information.
- type: textarea
id: environment
attributes:
label: Environment Details
description: Please add any information you can provide about the environment.
validations:
required: false
- type: textarea
id: description
attributes:
label: Description
description: Please provide a clear and concise description of the issue you are experiencing.
validations:
required: true
- type: textarea
id: debug
attributes:
label: Error or Debug Output
description: Please provide a link to a [GitHub Gist](https://gist.github.com/) containing the complete error or debug output.
placeholder: Link to a GitHub Gist. Please do not paste the debug output in the issue.
validations:
required: true
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: >
What is it you expected to happen?
This should be a description of how the functionality you tried to use is supposed to work.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: What actually happened that's different from the expected behavior?
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to Reproduce
description: Please provide the steps to reproduce the issue.
validations:
required: true
- type: textarea
id: logs
attributes:
label: Log Fragments and Files
description: >
Please include appropriate redacted log fragments. If the log is longer than a
few dozen lines, please include the URL to the
[Gist](https://gist.github.com/) of the log or use the [GitHub detailed
format](https://gist.github.com/ericclemmons/b146fe5da72ca1f706b2ef72a20ac39d)
instead of posting it directly in the issue.
validations:
required: false
- type: textarea
id: screenshot
attributes:
label: Screenshots
description: Screenshots of the issue, if applicable.
validations:
required: false
- type: textarea
id: references
attributes:
label: References
description: |
Please provide any related GitHub issues or pull requests (open or closed) or documentation.
Learn about [Referencing Github Issues](https://help.github.com/articles/basic-writing-and-formatting-syntax/#referencing-issues-and-pull-requests).
placeholder: |
#GH-0000
Every field exists for a reason:
| Field | Why It Matters |
|---|---|
Environment Details | Captures context that often determines whether the issue is real, reproducible, or already fixed elsewhere. |
Description | Forces the reporter to explain the problem in plain language before dropping logs or stack traces into the form. |
Error or Debug Output | Asks for a Gist link instead of a pasted wall of output, which keeps the issue readable. |
Expected Behavior and Actual Behavior | Separates "what should happen" from "what did happen", which is one of the fastest ways to make a bug report actionable. |
Steps to Reproduce | Turns the report into something another human can test. |
Log Fragments and Files, Screenshots, and References | Provides optional supporting material without making the form feel punitive. |
That balance is the goal. The form should be structured enough to make the issue useful, but not so burdensome that contributors give up halfway through.
GitHub Gists
Use a Gist link when the output is long enough that pasting it directly would make the issue hard to read. A short stack trace or a few lines of relevant log output can live in the issue itself. Full debug logs, large plan output, verbose traces, and multi-file examples are usually better in a Gist, with only the most relevant excerpt kept in the issue body.
Make Formatting the Default¶
One of the best GitHub issue form features is render: on textarea fields. It lets you tell GitHub how to wrap the submitted content automatically. This is the easiest way to improve the readability of configuration fragments, shell output, stack traces, and sample code.
For example:
- type: textarea
id: config
attributes:
label: Relevant Configuration
description: Provide the minimal configuration required to reproduce the issue.
render: yaml
validations:
required: true
- type: textarea
id: error-output
attributes:
label: Error Output
description: Provide the complete error output or stack trace.
render: text
validations:
required: false
With that in place, contributors don't need to remember Markdown fences or language identifiers. The form handles it for them. If your project routinely receives issues with YAML, JSON, HCL, shell output, or stack traces, this is worth adding immediately.
I covered the formatting side of this in more detail in Please Format Your Code Blocks: GitHub Issue Etiquette.
Issue forms let maintainers turn that etiquette into a default.
When You Need More¶
If you want to go beyond a minimal form, GitHub issue forms support much more than a few textareas. You can add checkboxes, dropdowns, project routing, labels, assignees, uploads, and markdown instructions directly in the YAML.
This is also where I like including a Code of Conduct acknowledgment. It's a small thing, but it does useful work. It sets expectations at the start of the interaction, reminds contributors that the issue tracker is a shared community space, and gives maintainers a clear reference point when they need to enforce standards of behavior later.
Here's a more complete example that shows what GitHub issue forms can do:
name: Bug
description: Report a bug or unexpected behavior in the library.
labels: ["bug", "triage"]
assignees: ["tenthirtyam"]
projects: ["tenthirtyam/67"]
type: bug
body:
- type: checkboxes
id: terms
attributes:
label: Code of Conduct
description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/tenthirtyam/example/blob/main/CODE_OF_CONDUCT.md).
options:
- label: I agree to follow this project's Code of Conduct.
required: true
- type: markdown
attributes:
value: |
Before filing an issue, please [search the existing issues](https://github.com/tenthirtyam/example/issues?q=is%3Aissue+is%3Aopen+label%3Abug) (open or closed), and use the [reaction](https://github.blog/2016-03-10-add-reactions-to-pull-requests-issues-and-comments/) feature to add up-votes to existing issues.
When filing an issue, please include the following information.
- type: input
id: version
attributes:
label: Library Version
description: |
Please provide the library version.
We recommend testing with [the latest version](https://github.com/tenthirtyam/example/releases/latest).
placeholder: e.g. 1.0.0
validations:
required: true
- type: input
id: go-version
attributes:
label: Go Version
description: What version of Go are you using?
placeholder: e.g. x.y.z
validations:
required: true
- type: dropdown
id: os
attributes:
label: Operating System
description: Select the operating system where the issue occurs.
options:
- Linux
- macOS
- Windows
- Other
validations:
required: true
- type: textarea
id: description
attributes:
label: Description
description: Please provide a clear and concise description of the issue you are experiencing.
validations:
required: true
- type: textarea
id: code-sample
attributes:
label: Code Sample
description: |
- Please provide a minimal, reproducible code sample that demonstrates the issue.
- Please ensure all sensitive information (passwords, hostnames, etc.) is removed.
render: go
validations:
required: true
- type: textarea
id: error-output
attributes:
label: Error Output
description: |
Please provide the complete error output or stack trace.
For large outputs, please use a [GitHub Gist](https://gist.github.com/).
render: text
validations:
required: false
- type: textarea
id: expected-behavior
attributes:
label: Expected Behavior
description: |
What is it you expected to happen?
This should be a description of how the functionality you tried to use is supposed to work.
validations:
required: true
- type: textarea
id: actual-behavior
attributes:
label: Actual Behavior
description: What actually happened that's different from the expected behavior?
validations:
required: true
- type: textarea
id: steps-to-reproduce
attributes:
label: Steps to Reproduce
description: Please provide the steps to reproduce the issue.
validations:
required: true
- type: upload
id: screenshots
attributes:
label: Upload Screenshots
description: Please upload any relevant screenshots or images that can help illustrate the issue.
validations:
required: false
- type: textarea
id: references
attributes:
label: References
description: |
Please provide any related GitHub issues or pull requests (open or closed) or documentation.
Learn about [Referencing GitHub Issues and Pull Requests](https://docs.github.com/en/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax#referencing-issues-and-pull-requests).
placeholder: |
#GH-0000
validations:
required: false
I wouldn't use this exact form in every repository. It's intentionally fuller than the minimal earlier examples. The point isn't to say every bug form should look like this.
The point is to show the range of what issue forms support, and how you can combine structure, guidance, and formatting defaults in one place.
Templates don't just make forms prettier. They encode the standards of the project at the exact moment someone needs them.
Resources¶
- GitHub Docs: Syntax for GitHub's issue form schema
- GitHub Docs: Configuring issue templates for your repository
- GitHub Docs: Creating a pull request template for your repository