Feature request template that becomes a changelog entry
6 min read
A feature request template is a form with four questions: what the person is trying to do, what stops them, what they tried instead, and how they want to be told when it is done. Everything else that usually appears on one, priority pickers, effort estimates, business value scores, is for the team receiving the request, and it is filled in wrongly by the person sending it.
Tidy requests are the wrong test for a template. The right one: six months later, when the feature ships, can someone find the request, understand it, and tell the person who wrote it? Most templates are designed for intake. This one is designed for the day the loop closes.
What should a feature request template include?
It should include the goal, the blocker, the workaround, and a way back to the requester. Four fields, in that order, each answering a question the team will ask later.
| Field | The question it answers later | Why it is on the form |
|---|---|---|
| What are you trying to do? | Is the feature we built the one they needed? | The goal outlives any specific proposal |
| What stops you today? | What does “done” look like? | Names the gap without prescribing the fix |
| What do you do instead? | How urgent is this, really? | A painful workaround is a stronger signal than a priority picker |
| How should we tell you? | Who gets the “shipped” message? | This is the field most templates leave off |
What is deliberately absent: a proposed solution as a required field (welcome as a comment, wrong as the framing), a priority picker (every submitter picks high), and any estimate of effort or value (the team’s job, after triage). A template that asks for a solution gets requests for buttons; a template that asks for a goal gets requests for outcomes, and outcomes are what a changelog entry is written about.
The template
This is the GitHub issue template we use, as a form. Paste it into
.github/ISSUE_TEMPLATE/feature_request.yml and it renders as a structured form on the New Issue
page. Requests filed through it land as issues with the same fields as the ones filed from a
feedback widget, which matters for the section after this one.
name: Feature request
description: What you are trying to do, and what stops you.
labels: ["feature-request"]
body:
- type: textarea
id: goal
attributes:
label: What are you trying to do?
description: >-
The outcome, not the button. "Export a month of invoices as one
PDF" beats "add a PDF export".
validations:
required: true
- type: textarea
id: blocker
attributes:
label: What stops you today?
description: >-
Where the product runs out. An error, a missing option, a limit.
validations:
required: true
- type: textarea
id: workaround
attributes:
label: What do you do instead?
description: >-
The spreadsheet, the script, the manual step. "Nothing, I gave
up" is a valid answer.
- type: input
id: contact
attributes:
label: How should we tell you when it ships?
description: >-
An email address, or leave blank to be notified only on this
issue.
Two details do the work. labels: ["feature-request"] means the request is classified at creation
rather than waiting for someone to triage it. And the last field exists because “we will let you
know” is a promise, and a promise needs an address.
Which labels should a feature request carry?
A feature request should carry one label for what it is, one for how urgent it is, and one for where it came from. Three labels, three axes, and each one is used by a different reader.
| Label | Values | Who reads it |
|---|---|---|
| Kind | feature-request, bug | The person deciding which queue it joins |
| Priority | priority:low, priority:medium, priority:high | The person planning the next cycle |
| Source | from-widget, from-form, from-support | The person measuring where requests come from |
The widget applies the first two axes and from-widget when it files a submission as an issue;
from-form and from-support are suggestions for requests that arrive other ways. The widget’s
labels are a
kind (bug or feature-request, decided by a classifier from the message alone), a priority (a
calm, specific crash report is high; a duplicate of something already asked is low; anything that
even hints at a security problem is bug and high, whatever the wording), and from-widget. The
same three axes work for requests that arrive by hand through the template above, which is the
point: a request is a request, wherever it entered.
One more convention: the widget strips the submitter’s email address out of the issue body before filing it, because the issue is in a repository that may be public, and replaces it with a submission reference. The address stays out of the issue; the submitter follows the outcome in the widget itself. Do the same with the contact field if your tracker is visible to anyone outside the team.
How does a feature request become a changelog entry?
A feature request becomes a changelog entry when a pull request closes the issue and the entry
drafted from that pull request links back to it. The mechanism is GitHub’s own closing keywords:
a PR whose description says Fixes #142 closes issue 142 on merge. If your changelog entries are
drafted from merged pull requests, the draft can carry the issue number with it, and the entry
knows who asked.
That is the reason the template asks for the goal rather than the solution. When the entry is written, the goal is the sentence the writer needs: “You can now export a month of invoices as one PDF” is a changelog entry. “Added PDF export” is a commit message. The changelog tools that draft from pull requests can do the collection and the linking; the wording still needs a person, and the person needs the goal.
What happens when it ships?
The requester gets told, with a link to the entry. In our setup that is automatic for requests that
came in through the widget: a comment reading “Shipped —
If you do this by hand, the rule is the same. Do not close the loop from the pull request. Close it from the published entry, and close it once. The feed and widget carry the same entry to everyone who did not ask, which is most people; the comment is for the one who did.
Why most feature request templates fail
They are designed to make triage easier and they succeed, at the cost of the only moment that matters to the requester. A template with twelve fields gets fewer requests, and the ones it gets are from people with the patience to fill in twelve fields, which is not the same population as the people who need the feature. A template with four fields, one of which is “how do we reach you”, gets more requests and can honour every one of them.
FAQ
Should a feature request template ask for priority? No. Ask for the workaround instead. “I export to a spreadsheet and re-key it every Friday” tells you more about priority than a dropdown the submitter set to high.
Should requesters propose a solution? They can, in the free text. Do not make it the framing. Requests written as solutions are harder to merge with each other and harder to write a changelog entry about.
Should feature requests appear on a public roadmap? Once they are planned, yes: a label on the same issue puts it in the planned column, and the requester can watch it move. The public roadmap article is the mechanism.
How do I handle duplicates?
Link the new request to the existing issue and label it low priority; do not close it. Each
duplicate is another person to tell when it ships. With Changeloop’s automatic comment, that
person is told only if the pull request also names their issue (Fixes #142, fixes #187).
Where should the template live? In the repository that will receive the pull request, so the closing keyword works. A request in a separate tracker has to be linked by hand at merge time, and that step is the one that gets skipped.
The technical claims in this article have not been independently reviewed. If something here is wrong, tell us and we will correct it.