How to Write Release Notes Users Will Read: A Guide for Indie Makers
A practical system for turning shipped work into clear product updates, migration guidance and a useful release archive.

Key takeaways
- Write for the person using the product: explain what changed, why it matters and what they should do next.
- Treat commit history as source material, then select, group and rewrite changes around user impact.
- Put breaking changes and migration instructions where affected users can see them before updating.
- Publish each release at a stable URL and distribute it through the channels that match its importance.
- Use release notes to invite previous visitors back only when the shipped change gives them a relevant new reason.
On this page 24
- TL;DR
- A current reminder: tell people what you shipped
- How to write release notes people can act on
- Choose what deserves a place
- Lead with value, then supply evidence
- Make the action unmistakable
- Release notes versus commit logs
- A lightweight collection workflow
- How to explain breaking changes and migrations
- Clearly labelled example migration note
- A release notes structure you can reuse
- Clearly labelled example template
- New
- [Outcome-led change title]
- Improved
- Fixed
- Breaking changes
- [Affected feature or interface]
- Get help
- What good public examples teach
- Where to distribute release notes
- Build an archive that stays useful
- Turn a release into a reason to return
- Final editing pass
To learn how to write release notes, explain what changed, who benefits, what the user can do now, and any action required. Lead with the most valuable change, group the rest by user impact, state the release date and version, and put breaking changes beside clear migration steps and deadlines.
Disclosure: ZeroRaised publishes this guide and makes no promise of traffic or results.
TL;DR#
Release notes are edited product communication, not a pasted engineering record. Start with the outcome a user can now achieve. Follow with the changes that matter to that outcome, name affected plans or platforms, and finish with any action, limitation or support route. Keep internal implementation detail only when it changes a user's decision.
Use this compact order:
- Name the release, version and date.
- Summarise the most useful change in one or two sentences.
- Group notable items under plain labels such as New, Improved, Fixed and Breaking.
- Explain each item as outcome, context and action.
- Put migration instructions directly beside a breaking change.
- Link to deeper documentation only after the essential instruction is present.
- Publish at a permanent URL, then share the update where affected users already interact with the product.
Keep a Changelog recommends a human-curated list of notable changes, grouped by type and ordered with the newest release first; it also warns that commit-log diffs contain noise (checked 18 Oct 2026). That is a sound baseline, but an indie product can use warmer, more specific language than a repository file.
| Document | Main reader and job | Suitable content | Poor fit |
|---|---|---|---|
| Release notes | Users evaluating one shipped release | Outcomes, visible changes, affected users, required action, limitations | Every internal task and refactor |
| Changelog | Users who need an ordered history | Dated releases, versions, notable additions, changes, removals, fixes and security items | A campaign with no durable archive |
| Commit log | Contributors tracing code history | Atomic implementation steps, merges and technical references | Unedited customer communication |
This distinction follows the purpose described by Keep a Changelog: commits document steps in source-code evolution, whereas a changelog serves people who need to understand notable differences between releases (checked 18 Oct 2026).
A current reminder: tell people what you shipped#
On 17 Oct 2026, Simon Green published “Don't Be One of Them”, an essay prompted by the release notes on his phone. Green says that eleven of twelve pending app updates used vague wording such as generic bug fixes and small improvements. His argument is modest and useful: users do not need the commit history, but they do deserve a couple of sentences explaining what changed and why it matters (Simon Green's essay, checked 18 Oct 2026).
The essay was shared on Hacker News on 17 Oct 2026, where the item linked directly to Green's piece (checked 18 Oct 2026). The lesson is not that every maintenance release needs an essay. It is that “improvements” makes the reader do all the interpretive work. If you repaired exports that failed on large files, say that. If nothing in the release is meaningful to a particular user group, do not manufacture importance.
A small team has an advantage here. The person who understands the change may sit close to the support conversation that prompted it. Capture that context while the work is fresh, then remove the internal vocabulary before publishing.
How to write release notes people can act on#
Begin with the user's situation, not the component you touched. “Added asynchronous job retries” describes implementation. “Imports now resume after a temporary connection failure, so you no longer need to restart the file” describes observable behaviour. Both may be accurate, but only the second helps a user decide whether to try again.
For every candidate item, answer five editorial questions:
- What changed in the product? Name the visible behaviour, capability or restriction.
- Who is affected? Specify a role, plan, platform, integration or workflow when the change is not universal.
- Why does it matter? Connect the change to a task, problem or previous limitation.
- What should the reader do? Say “nothing” through omission when no action is needed; give an exact next step when one is.
- Where can they verify the detail? Link to documentation, a migration guide, status information or support.
These are editing questions, not fields that must appear as labels. A concise note may answer all five in two sentences. A risky change may require its own section.
Choose what deserves a place#
Include work that changes a user's capability, result, required action, compatibility, security posture or decision to adopt the product. Include a fix when readers can recognise the symptom, especially if support has already discussed it. Include a deprecation before removal, not only when the old behaviour disappears. Include a limitation when it sets a boundary around the new feature.
Leave out routine dependency bumps, internal renaming, test changes, refactors and build-pipeline work unless they alter supported environments, performance, security or observable behaviour. Several internal changes can become one user-facing item when they produce one result.
Keep a Changelog uses the headings Added, Changed, Deprecated, Removed, Fixed and Security, and advises keeping an Unreleased section to collect upcoming items (checked 18 Oct 2026). You can adopt those exact categories or use fewer labels. The useful practice is consistent classification, not ceremony.
Lead with value, then supply evidence#
Put the change with the broadest or most urgent user impact first. The first line should stand on its own in an email preview or in-product panel. Avoid opening with greetings, internal release codenames or a list of tickets.
Then add evidence a reader can inspect: the affected screen, supported format, changed default, removed option or corrected behaviour. “Reports load faster” is weak without context. “The report view now opens without waiting for archived projects to finish loading” identifies what changed without inventing a timing claim.
Use the user's nouns. If the interface calls an object a workspace, do not call it an organisation in the notes. If customers report “duplicate invoices”, keep that phrase instead of translating it into the internal service name. Consistent vocabulary helps support, documentation and the product reinforce one another.
Make the action unmistakable#
Write the required action as a command with an owner and a time. “API updates available” does not say enough. “Workspace admins must replace the old webhook endpoint before 30 November” states who, what and when. Only publish a date that your team has actually chosen and can support.
Place the action beside the reason. Do not hide a required migration behind “Learn more”. A linked guide can contain screenshots, alternatives and edge cases, but the release note should still tell the reader whether they are affected and what they must do next.
Release notes versus commit logs#
A commit log is useful raw material because it can reveal what merged, who contributed and which issue or pull request holds the detail. It becomes poor release copy when it exposes work in implementation order, repeats merge noise or assumes the reader knows internal labels.
GitHub's generated release notes can produce a list of merged pull requests, a contributor list and a link to the full changelog. GitHub also lets maintainers use labels to create categories and exclude selected labels or users from the output (GitHub's generated release notes documentation, checked 18 Oct 2026). That makes generation a useful collection step, not a reason to skip editing.
Use this translation pass:
| Raw development wording | Editing question | Example user-facing rewrite |
|---|---|---|
Fix #842 null state in CSV worker | What did the user experience? | “CSV imports no longer stop when an optional cell is empty.” |
Add provider_x adapter | What can someone do now, and who can do it? | “Example: Pro workspaces can now connect Provider X from Settings.” |
Refactor auth middleware | Did observable behaviour change? | Omit it if the answer is no. |
Remove legacy tokens | Who used them, what breaks and what replaces them? | “Example: Legacy API tokens stop working on 30 November. Create a scoped token before that date.” |
All text in the final column is a clearly labelled illustrative example, not a claim about a named product. Replace placeholders, plans and dates with verified facts from your own release.
A lightweight collection workflow#
Add one short “user impact” field to the pull request or task template. Ask the author to describe the behaviour before and after the change, affected users, rollout conditions and whether action is required. “No user-facing change” should be a valid answer.
At release time, generate or gather the merged work, remove items with no user impact, combine duplicates, and sort what remains by importance. Ask the person closest to support or product to challenge unclear terms. Ask an engineer to verify technical accuracy. For a breaking release, ask someone who did not build the change to follow the migration steps in a clean environment.
Automation should reduce omission, not decide importance. A script can assemble pull requests and authors. Labels can suggest categories. A person still needs to decide whether five technical tasks represent one benefit, whether a known limit must be disclosed, and whether the headline overstates the result.
Maintain a small release-note queue during development rather than reconstructing every choice at the end. The Unreleased section recommended by Keep a Changelog is one established way to hold upcoming items until they move into a versioned section (checked 18 Oct 2026).
How to explain breaking changes and migrations#
A breaking change gets priority over promotional copy because it can interrupt a working integration. Put a plain warning near the top, name the affected interface or behaviour, state when the change takes effect, provide the replacement, and link to a tested migration guide.
If your public API follows Semantic Versioning, version numbers carry a defined compatibility signal: increment the major version for incompatible API changes, the minor version for backward-compatible functionality and the patch version for backward-compatible bug fixes (Semantic Versioning 2.0.0, checked 18 Oct 2026). A version number does not replace prose. Readers still need to know which calls, settings or files change.
Write a migration block in this order:
- Affected: the plans, versions, endpoints, clients or operating systems in scope.
- Change: the old behaviour and the new behaviour.
- Timing: availability, deprecation and removal dates, where those dates exist.
- Action: a numbered path that starts from the user's current state.
- Verification: a way to confirm the migration worked.
- Fallback: rollback, compatibility mode or support route, if offered.
Keep the deprecation visible across relevant releases. Keep a Changelog says it should be clear when an upgrade will break and advises listing deprecations, removals and breaking changes even if nothing else is documented (checked 18 Oct 2026). That continuity matters because users may skip intermediate versions.
Stripe's public API changelog marks entries as breaking changes and places an “Upgrade your integration” route alongside its versioning material, giving developers a place to connect change history with upgrade work (Stripe API changelog, checked 18 Oct 2026). The transferable lesson is structural: separate compatibility risk from ordinary improvements and lead affected readers towards action.
Clearly labelled example migration note#
Example only: API token migration
Breaking change: Requests using legacy workspace tokens will be rejected after 30 November 2026.
Affected: Integrations that send tokens beginning with
old_. Scoped tokens are unaffected.Action: Create a scoped token in Settings, replace the stored credential, make a test request, and confirm the response appears in the integration log.
Need more time? Contact support before the deadline to discuss the documented fallback available for your account.
Every name, prefix, date and fallback in that box is illustrative. A real note must use the actual identifier, deadline, tested steps and support policy. Never imply that a fallback exists until it has been approved.
A release notes structure you can reuse#
Use a repeatable skeleton so the team spends its judgement on the message, not on rebuilding the page. Remove empty categories rather than publishing rows that say “none”.
Clearly labelled example template#
# [Release name or version]
Released: [DD Month YYYY]
[One or two sentences stating the main user outcome and who benefits.]
## New
### [Outcome-led change title]
[What changed, why it matters, who can use it, and any limitation.]
## Improved
- [Specific behaviour that is now clearer, faster or more reliable, with verified context.]
## Fixed
- [Recognisable symptom] no longer [previous unwanted result].
## Breaking changes
### [Affected feature or interface]
- Affected: [users, plans, versions or platforms]
- Action: [required steps]
- Deadline: [date, if applicable]
- Migration guide: [permanent documentation URL]
## Get help
[Support route and relevant documentation]
The template is an example, not a universal standard. A small visual update may need only a title, screenshot, explanation and link. A security release may need careful disclosure coordinated with the fix. An API removal needs complete migration detail even if the resulting note is longer.
Keep each bullet atomic. If a bullet joins a new feature, a fix and a warning, split it. Give every subheading a meaning outside the release context. “A clearer billing history” is more useful in an archive than “More improvements”.
Use images only when they reduce ambiguity. Add a caption or surrounding text that explains what the image demonstrates. Do not make a video the only place where required steps appear. Text remains easier to scan, search, quote in support and revise when guidance changes.
What good public examples teach#
Named product archives show several legitimate formats. Copy the principle that fits your audience, not the surface style of a much larger team.
| Public example | Observable structure | Useful lesson for an indie maker |
|---|---|---|
| GitHub Releases | A release can package software with notes and links to binary files; notes may be written manually or generated from a template | Keep distributable files, version context and explanation together when users install releases |
| Slack release notes | Separate navigation exists for iOS, Android, Mac, Windows, beta and Linux notes | Split archives when platform-specific changes would otherwise confuse readers |
| VS Code updates | The update page has an “In this update” index, deprecated-feature material and access to previous versions | Give long notes a contents path and keep old versions reachable |
| Stripe API changelog | Entries visibly distinguish breaking changes and connect to integration upgrade guidance | Make compatibility risk easy to scan and pair it with a next step |
Sources: GitHub on releases, Slack release notes, VS Code updates and Stripe API changelog, all checked 18 Oct 2026.
Notice that none of these structures requires a small product to imitate enterprise volume. The useful choices are audience split, scan order, compatibility warnings, version history and access to deeper detail.
Where to distribute release notes#
The permanent changelog is the source of record. Distribution brings the relevant entry to people who may benefit or need to act. Choose the channel according to consequence, not excitement inside the team.
| Channel | Use it when | Keep the message focused on | Main risk |
|---|---|---|---|
| In-product notice | The change affects a current workflow or needs timely action | What changed here and the immediate next step | Interrupting people who are unaffected |
| A subscribed or operational audience needs a useful summary or warning | Outcome, affected group, deadline and permanent note | Sending minor changes too broadly | |
| Public changelog page | You need a durable, searchable release history | Full edited note, date, version and stable links | Letting it become an unedited task dump |
| Documentation | Set-up, reference or migration behaviour changed | The current correct procedure | Leaving old instructions beside new behaviour |
| Support reply | A shipped fix answers a reported problem | The symptom, resolution and how to retry | Making a private reply the only announcement |
| Release post | The update gives a wider audience a genuine reason to reconsider the product | User problem, shipped result and proof | Re-announcing cosmetic work as a major event |
These channel choices are editorial guidance. Apply your consent, service-message and account rules before sending email or in-product communications.
Do not paste the entire note everywhere. An in-product message can state the result and link to the permanent entry. An email can select the changes relevant to that audience. Documentation should describe the current product rather than preserve announcement language. Support can link a specific fix to the conversation that reported it.
For a substantial public release, work through the product release checklist before inviting attention. If you are deciding between launch venues, use where to launch a SaaS to match the product and audience rather than copying the same announcement across communities.
Build an archive that stays useful#
Give each release a stable URL, visible date and version or release name. Put the newest entries first on the index, then retain older entries rather than silently replacing them. Keep a Changelog recommends one entry per version, the latest version first, release dates in an unambiguous standard format and marking releases that were withdrawn because of serious issues (checked 18 Oct 2026).
A practical archive has three levels:
- Index: release title, date, brief summary, categories and link.
- Release page or anchor: the complete edited note and migration warnings.
- Deep documentation: the current set-up, reference or migration procedure.
Keep old release prose historically accurate while updating dangerous or broken instructions with a clearly dated correction. If a release is withdrawn, label it instead of removing the evidence. If a migration deadline changes, add a dated update and make the current date unmistakable.
Add filters only when the archive has enough material to justify them. Useful dimensions might include platform, product area, API version or change type. Begin with good titles and consistent categories. Search and filtering cannot rescue vague entries.
Link related releases when a capability develops over several versions. A reader arriving from an old support ticket should be able to move from the initial announcement to the current documentation without guessing which post superseded which.
Turn a release into a reason to return#
A release note can reopen a conversation with someone who left because of a specific limitation. It should not pretend that every past visitor wants every update. Match the shipped change to the reason the person previously hesitated.
Start with evidence you already have: support requests, interview notes, cancellation reasons and replies to earlier launches. If several people asked for an export format and you have now shipped it, write the note so they can verify the exact format and limits. Contact only people you are permitted to contact, and make the message about their stated problem rather than your release calendar.
A useful return message has four parts:
- Remind the reader of the problem they raised.
- State what has changed without claiming that every edge case is solved.
- Link to the release note and the current documentation.
- Invite a specific test or reply.
When the improvement is substantial enough for a fresh public release, eligible products can use the ZeroRaised submission page. ZeroRaised is for products with no institutional VC or accelerator equity (submission details, checked 18 Oct 2026). Read the eligibility information before presenting an update, and use /submit rather than treating a release note as an automatic route to attention.
The maker perks page is a separate resource for eligible makers, not a distribution promise (checked 18 Oct 2026). No archive, email or release venue guarantees that visitors will return. The honest objective is to give the right previous visitor a clear, verifiable reason to look again.
Final editing pass#
Before publishing any release note, read it once as a new user and once as an affected existing user.
For the new user, check:
- Can they understand the outcome without knowing the old interface?
- Does the note explain who the product change is for?
- Are screenshots, examples and plan names current?
- Does the link lead to instructions that match the shipped behaviour?
For the existing user, check:
- Can they see whether their workflow changes?
- Are deprecations and removals prominent?
- Is every required action complete, ordered and tested?
- Are dates, versions, identifiers and compatibility statements verified?
- Can they find help without searching the whole site?
Then remove filler. Replace “We are excited to announce” with the result. Replace “various fixes” with a recognisable symptom or omit it. Replace internal project names with product language. Separate verified fact from intended benefit: “You can now export JSON” is a product fact; “this will save hours” is an outcome claim that needs evidence you may not have.
Finally, check the release against the product itself. Open the named screen, follow the migration, test the link and confirm the version. The best answer to how to write release notes is simple: edit from the user's point of view, show the consequence of the work, and make the next action safe to follow.
For a visual companion to a substantial update, follow the product demo video guide.
Frequently asked questions
How do you write good release notes?
State what changed, who benefits, why it matters, what action is required and where to find more detail. Put the most important user outcome first.
What should be included in release notes?
Include a release date, version or release name, a short summary, user-facing changes, fixes that affect behaviour, breaking changes, migration steps and relevant support links.
Are release notes the same as a changelog?
Release notes explain one shipped release to its audience. A changelog is the ordered archive of notable changes across releases, while a commit log records development history.
Should release notes include every commit?
No. Use commits and merged pull requests as source material, then remove internal noise, combine related work and explain the result in language users understand.
Where should release notes be published?
Keep a permanent changelog page, then point affected users to each update through suitable in-product messages, email, documentation, support replies and release announcements.