How to write a changelog (with examples)
A changelog is the simplest piece of product communication you can ship, and one of the most neglected. (New to the idea? Start with what a changelog actually is.) This guide covers what goes in one, how to phrase entries, how often to post, and how to automate the whole thing so it never goes stale.
Who a changelog is for
Not you. A commit log is for you; a changelog is for the people who use the thing. That single idea drives every rule below: write about outcomes, not diffs. Your users don't care that you "refactored the session middleware" — they care that "you no longer get logged out when your laptop sleeps." If your audience isn't developers at all, there's a whole craft to writing release notes for non-technical users.
The structure that works
Every entry needs exactly three things:
- A date. Changelogs are timelines. An undated entry is a rumor.
- A one-line, human title. Verb first, outcome-oriented: "Import your existing CHANGELOG.md", not "Importer module v2".
- A tag. One word that tells scanners what kind of change it is. Four tags cover almost everything: new, improved, fix, announcement. (The Keep a Changelog convention uses Added / Changed / Fixed / Removed / Deprecated / Security — same idea, more granular. Pick one vocabulary and stick to it.)
Body text is optional. Add it when the title needs a "why", a screenshot, a code sample, or a migration note. Skip it when the title says everything.
Good entry, bad entry
Bad (a commit message wearing a hat):
fix: race condition in queue consumer when redis reconnects (#482)
Good (same change, written for users):
Fixed: background jobs no longer occasionally run twice If your webhook fired twice during a brief outage on our side, this was why. Jobs are now exactly-once even across reconnects.
The difference: the good one names the symptom the user saw, admits the impact, and says what's true now. That builds more trust than a hundred silent fixes. For more of this in the wild, see what great products get right in their changelogs.
Phrasing rules that keep you honest
- Past tense or present result — "Added dark mode", "Exports now include drafts". Never future tense; a changelog is a record, not a roadmap.
- Name the pain when fixing. "Fixed slow dashboard loads for projects with 1,000+ posts" beats "Performance improvements."
- Never hide breaking changes. Put "Breaking:" at the front of the title and the migration path in the body. Users forgive breakage; they don't forgive surprise. (Full playbook: how to announce breaking changes.)
- Cut the adjectives. "Blazing fast", "revamped", "supercharged" age badly. Numbers don't: "search is ~4× faster on large projects".
Register and personality are their own topic — see changelog tone and voice.
How often to post
Whenever something a user could notice ships. For most indie projects that's somewhere between weekly and monthly (picking a release-notes cadence goes deeper). Two failure modes to avoid:
- The dead changelog — last entry eight months ago. Worse than none: it reads as "this product is abandoned". If you shipped nothing user-visible for a while, a short "still here — this month was infrastructure work" announcement keeps the pulse.
- The firehose — every commit, every typo fix. Batch small fixes into one weekly "fixes" entry with bullets.
Automate it or it dies
The number one reason changelogs go stale is that updating them is a separate, manual chore that lives outside the release flow. Fix that structurally:
- Make the changelog entry part of your release script — the same script that tags and deploys should post the entry (wiring it into GitHub Actions or any CI).
- Or drive it from release webhooks: publish a GitHub/GitLab release and let it mirror to your public changelog automatically.
- Write the entry before you ship, as a draft, while the change is fresh — then publish it (or schedule it) when the deploy lands.
If you want your git history to write the first draft for you, see generating a changelog from git commits — just treat the output as a draft, not the entry.
A template to steal
## [Tag] Verb-first title users understand — YYYY-MM-DD One sentence on why this matters or what changed for you. - Detail or sub-change - Migration note if any
Want more? Release notes templates has copy-paste skeletons for features, fixes, breaking changes, security fixes, and more.
Where Wakelog fits
Wakelog is a free hosted changelog built around exactly this workflow: entries are
title + tag + optional markdown body, posting is one curl or
wakelog post at the end of your deploy script, GitHub/GitLab release
webhooks post for you, and drafts + scheduled publishing cover the "write it before you ship
it" habit. You get a public page, RSS, and an in-app "what's new" widget — and you can export
everything back to a plain CHANGELOG.md anytime.
Preview your CHANGELOG.md — no signup Start a free changelog
Related guides
- Release notes templates: copy-paste formats for every kind of change
Seven fill-in-the-blank templates — feature, fix, breaking change, security, app store, API, digest — and the questions each one answers. - Changelog examples: what great products get right
Six very different products with excellent changelogs — and the one specific habit worth stealing from each. - The changelog field guide: how to announce anything you ship
One hundred guides is a library, not an answer. This is the lookup table: match what you’re shipping, who receives it, and where they’ll read it — and read only the two or three guides that cover exactly that.
Last updated 2026-07-28 · All guides