How to write release notes people actually read
Most release notes are written for the person shipping, not the person reading. Here is the shape that gets read, with examples of the same entry written badly and well.
4 minute read
Most release notes are written by the person who shipped the work, in the language of the work. "Refactored the export pipeline; POST /v2/exports now returns 202." True, and useless to the person who wanted their spreadsheet on Monday.
Release notes are a product surface. They are read by customers deciding whether you are still worth paying for, by prospects checking whether you are alive, and by your own support team looking for something to link to. This is what works.
Write the entry from the reader's side
Start with what someone can now do, not what you changed.
Weak:
Migrated the notification service to a queue-backed worker.
Better:
Emails now arrive in seconds, not minutes. Notifications used to be sent as part of the request that triggered them, so a busy afternoon could delay them. They are now queued and sent on their own.
The second version still contains the technical fact. It just leads with the part the reader can feel.
Use a shape, and keep it
Every entry that gets read has roughly the same shape:
- A title that is a sentence. "Dark mode" tells a reader nothing they did not already guess from the word. "Dark mode, and it follows your system setting" tells them whether to care.
- One sentence on what changed.
- One sentence on why, or what it replaces. This is the part teams cut, and the part that earns trust.
- A link, if there is more to know: the documentation, the setting, the page it happens on.
- A picture, only when the change is visual. A screenshot of a settings toggle helps. A screenshot of a paragraph does not.
Tag entries, but only three ways
Three categories cover almost everything a customer cares about:
| Tag | Use it for |
|---|---|
| New | Something that did not exist before |
| Improved | Something that existed and now works better |
| Fixed | Something that was broken and a customer could have noticed |
More categories than that, and you will spend your Fridays deciding between "Enhancement" and "Optimisation" while your readers treat them as the same word.
What to leave out
- Internal work with no visible effect. Dependency upgrades, refactors, test coverage. Put them in your repository's changelog, not your customers'.
- Version numbers as titles. "v2.4.1" is not an announcement. It is a filename.
- Apologies in the title of a fix. State the fix plainly. "Fixed: invoices dated in the wrong month" is more reassuring than a paragraph of regret.
- Anything you cannot say publicly. If half the entry has to be vague, ship it as documentation instead.
Publish on a rhythm, not on a whim
A changelog that is updated weekly builds an expectation. One that goes quiet for three months and then lists forty things reads as a company that went quiet for three months.
If you ship continuously, batch the small things into one weekly entry and give the big things their own. If you ship rarely, publish anyway: "nothing shipped this week, here is what we are working on" is a legitimate entry for a small team, and it is how people learn you are still there.
Put it where people already are
Three places, and they are not alternatives:
- A page of its own, on your domain, so it can be linked, indexed and shared.
yourcompany.com/changelog, not a subdomain of a tool. - In your product, as a small widget, so someone who logs in after a fortnight sees what changed while they were away.
- In email, for the people who asked for it. One email per release, not a monthly digest that lands after everyone stopped caring.
The same entry can serve all three. Write it once.
Write the entry before you ship
The clearest test of whether a feature is finished is whether you can describe it in three sentences without using the word "and then". Writing the note first turns that into part of the work rather than a chore you do on Friday afternoon with the pull request titles as your only source.
A worked example
Here is a real-shaped entry with all of it applied:
Import your history from any changelog tool
Improved · 18 September 2026
Moving from another tool no longer means losing what you have already written. Paste your old changelog's feed address, or upload a CSV or a
CHANGELOG.md, and every entry comes across with its original date.You see exactly what will be imported before anything is saved, and anything already on your changelog is skipped. Your subscribers are not emailed about imported entries — they have read them already.
Title says what you can do. First paragraph says how. Second paragraph answers the two questions a careful reader would have asked next.
Questions
- How often should you publish release notes?
- Whenever something ships that changes what someone can do. For most small teams that is weekly. A predictable rhythm matters more than volume, and a quiet week is better than an entry padded with internal work nobody asked for.
- Should release notes include bug fixes?
- Include fixes that a customer noticed or reported, written as the problem they saw. Leave out internal refactors, dependency bumps and anything a reader could not have experienced.
- How long should a release note be?
- A title someone can scan, then two or three sentences. If it needs more, the extra belongs in your documentation, linked from the entry.
- What is the difference between a changelog and release notes?
- A CHANGELOG.md in a repository is written for developers and ordered by version. Release notes are written for customers and ordered by date. Many teams keep both, and copy the customer-facing subset across.
Your changelog, on your own domain
One plan at $19 a month: your domain, the widget, subscriber emails, no watermark and no trackers on your readers. Writing is free — a card starts the 7-day trial when you publish.
Free tools
- Changelog Grader Score any public changelog out of 100, with the reasons.
- Release Notes Generator Turn commit messages into release notes, in your browser.
- CHANGELOG.md Validator Check a CHANGELOG.md against Keep a Changelog, line by line.