Most changelog examples you find online are screenshots of pretty pages. That is not the problem teams actually have. The problem is the line: what do you write on the day you ship, so that someone who did not build the thing understands what changed and whether it affects them.

So this is a guide to the line. The format first, then ten entries lifted verbatim from public changelogs, then the same change written badly and written well. The argument underneath it is the one that keeps resurfacing on Hacker News: changelogs get written for the people who built the software, and read by people who did not.

Who is a changelog actually for?

A changelog is for the person who did not build the software and has to decide whether to upgrade. That single sentence settles most formatting arguments, because it rules out anything that only makes sense if you already know the codebase.

The clearest statement of this comes from Aurélien Gâteau, in an essay on why a git log is not a changelog published in July 2022: “Git commit messages and changelogs do not have the same target audience.” The changelog targets users, and has to answer questions like “Is this annoying bug fixed?” and “Is it safe to upgrade, or do I need to adjust my code/workflow to this new version?”. Commit messages target contributors, and the question they answer is why a change was made. Generating one from the other, he argues, means you “optimize your commit messages for your users, but the target audience for your commit messages are contributors”.

Keep a Changelog, the convention maintained by Olivier Lacan and now at version 1.1.0 in 28 languages, opens with the same idea in four words: “Changelogs are for humans, not machines.” Asked who needs one, it answers: “People do. Whether consumers or developers, the end users of software are human beings who care about what’s in the software.”

The failure mode has a name, and it is the phrase every app store update screen is full of. In January 2021 Remy van Elst published a rant about “bugfixes and performance improvements” that collected 241 points and 120 comments on Hacker News. His objection is not aesthetic, it is practical: “For me as a technical user it’s not actionable, and your non technical users are not going to read that page anyway.” He describes disabling auto updates and reading the changelog to decide whether to update now or later, and ends with a line worth pinning above the release checklist: “Not all change is progress, but please, please tell me what changed.”

A commenter in that thread names the cost exactly: “The worst changelogs are the ones that say ‘Performance improvements and bugfixes’ only to find out the entire user interface has changed after updating.” A vague entry does not save the reader time. It transfers the work to them, after the upgrade, when it is expensive. If you are still deciding whether the file is worth keeping at all, we made that case in do you already keep a changelog.

What is the standard changelog format?

There is no official standard changelog format, and the most widely used convention says so itself. Keep a Changelog’s own FAQ answers the question “Is there a standard changelog format?” with “Not really”, noting that the GNU changelog style guide and the two-paragraph GNU NEWS guideline are “both inadequate or insufficient”, and describing itself as a convention gathered from open source practice rather than a specification.

What exists instead is a convention that won by adoption. Six categories are the whole of it.

Sorting tray with six labelled compartments, one for each changelog category: Added, Changed, Deprecated, Removed, Fixed and Security

Category Use it for Example entry
Added New features Added SSO support for Okta and OneLogin.
Changed Changes in existing functionality Changed the default export format from CSV to XLSX.
Deprecated Soon-to-be removed features Deprecated the v1 webhook payload. It will be removed in 3.0.0.
Removed Now removed features Removed the legacy dashboard and its routes.
Fixed Any bug fixes Fixed a crash when a project name contained an emoji.
Security Vulnerabilities Patched a path traversal issue in file uploads.

Four rules carry the rest of the value.

  1. Newest first. The top of the file is the most recent release. Nobody scrolls to find out what just shipped.
  2. Date every version in ISO 8601. Write 2026-09-20, not 09/20/2026. Keep a Changelog recommends it because the ordering runs largest unit to smallest and does not collide with regional formats that swap month and day.
  3. Pair it with Semantic Versioning. Major for breaking changes, minor for backwards compatible additions, patch for fixes. The version number then tells the reader how carefully to read the entry.
  4. Keep an Unreleased section at the top. Changes accumulate there between releases, so writing the changelog stops being a release day scramble and becomes a line added with each merge. This is the single habit that keeps changelogs alive.

Two more conventions are worth knowing. A release pulled for a serious bug or security issue gets a loud [YANKED] tag on its heading, written as ## [0.0.5] - 2014-12-13 [YANKED], so nobody installs it by accident. And if you do nothing else on this list, do the deprecations: “If you do nothing else, list deprecations, removals, and any breaking changes in your changelog.” Inconsistency is the quieter failure. A changelog that records only some changes, the convention warns, “can be as dangerous as not having a changelog”, because readers treat it as the source of truth while it quietly is not one.

A CHANGELOG.md template you can copy

Save this as CHANGELOG.md in your repository root and add lines to Unreleased as you merge.

# Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog,
and this project adheres to Semantic Versioning.

## [Unreleased]

### Added

## [2.1.0] - 2026-08-07

### Added

- Bulk import for CSV files up to 50 MB.
- Keyboard shortcut for the command palette.

### Changed

- Search now matches on tags as well as titles.

### Fixed

- Fixed timezone drift on scheduled exports.

## [2.0.1] - 2026-07-22

### Security

- Patched an authorisation gap on shared board links.

## [2.0.0] - 2026-07-15

### Removed

- Removed the v1 API. See the migration guide.

### Deprecated

- The legacy webhook payload will be removed in 3.0.0.

That file is the record for developers. If you also publish a customer-facing version, write it second and keep it shorter: most releases deserve one sentence and a screenshot. Our five release notes templates, each with a worked example, cover the product, in-app, API breaking change and enterprise variants of that second document.

10 changelog examples from real products

These are quoted verbatim from public changelogs, chosen because the wording does the work, not the page design.

Entry, verbatim Where it is from Why it works
Use explicit platform fonts instead of system-ui and ui-sans-serif so CJK text respects the page’s lang attribute on Windows Tailwind CSS 4.3.3, 2026-07-16 Names the platform, the language and the symptom, so you know in one read whether it was your bug
Prevent Preflight from overriding Firefox’s native iframe:focus-visible outline styles Tailwind CSS 4.3.3, 2026-07-16 Browser and component named. No ticket to open, no diff to read
Support --watch --poll[=ms] in @tailwindcss/cli when filesystem events are unreliable or unavailable Tailwind CSS 4.3.3, 2026-07-16 States the condition under which you would want the new flag, not just that it exists
Block pull requests with exposed secrets from merging GitHub Changelog, 2026-09-09 Verb first, outcome only, seven words. Nothing about how it was built
Profiles now show your highest achievement badge tier GitHub Changelog, 2026-09-11 “Now” plus what the reader will see the next time they look
Upcoming deprecation of selected GitHub Copilot models in mid-October GitHub Changelog, 2026-09-18 Announces the removal before it happens and says roughly when
SHA-1 in HTTPS on GitHub sunset GitHub Changelog, 2026-09-15 A removal stated plainly, with the thing removed named precisely enough to check your own client
SCIM user responses now include a profileUrl attribute GitHub Changelog, 2026-09-16 Additive API change with the exact field named, which is what an integrator needs to grep for
Warn on binary patterns with segments that are not byte-aligned Elixir v1.21 CHANGELOG, under Kernel The module prefix acts as a filter: readers skip whole sections that do not touch them
Adds new account requirement error codes to the Accounts API Stripe API changelog Verb first, API surface named, one change per entry

Stripe is worth studying for its filing rather than its prose. Every API change gets its own dated URL and page, and every title starts with one of a small set of verbs: Adds, Removes, Renames, Deprecates. That makes a single change linkable from a support reply three years later, which is the property most changelogs lack.

What the good entries share is not design. It is a permanent address per entry, a date on everything, consistent categories, and a sentence that survives being read alone by someone who was not in the standup.

How do you write a changelog entry?

Write it as verb, object, consequence: what you did, what it touched, and what the reader now has to do about it. Most entries need only the first two; breaking changes, removals and anything that alters a default always need the third.

Two index cards side by side, the left one struck through in red, the right one rewritten and clean

The fastest way to see the difference is to put the version your team would write next to the version that shipped.

Written for the team that built it Written for the reader, verbatim from a real changelog
Updated the default font stack. Use explicit platform fonts instead of system-ui and ui-sans-serif so CJK text respects the page’s lang attribute on Windows.
Bug fixes and performance improvements. Block pull requests with exposed secrets from merging.
Deprecated some models. Upcoming deprecation of selected GitHub Copilot models in mid-October.
See PR #20297 for details. Support --watch --poll[=ms] in @tailwindcss/cli when filesystem events are unreliable or unavailable.

Three habits produce the right-hand column. Start with the change in past or present tense, because the category heading already says which kind it is and the verb keeps the line scannable when it gets quoted out of context. Name the thing in the user’s vocabulary, not the class name: if a reader cannot search your docs for the noun you used, you used the wrong noun. And state the consequence when there is one, which is the clause Keep a Changelog cares about most.

Skip ticket numbers unless your readers can actually open them. A private issue ID in a public changelog is a closed door with a label on it.

Changelog versus release notes: what is the difference?

A changelog is the complete, cumulative record of every notable change; release notes are a selective announcement of one release. Teams use the words interchangeably, but the two documents fail in opposite directions, so it helps to keep them apart.

Changelog Release notes
Audience Users and developers tracking every version Users deciding whether to care about this release
Scope Every notable change, complete and cumulative Selected highlights of one release
Format Terse, categorised, one line per change Narrative, with context, screenshots and links
Cadence Every version, without exception Per release, sometimes only for significant ones
Lives in CHANGELOG.md or a public feed A post, an email, an in-app announcement

The record must be complete or it is worthless. The announcement must be selective or nobody reads it. We covered the announcement side separately in a guide to improving your release notes.

Can AI write your changelog?

It can write the draft. It should not decide the contents.

A model reads the merged pull requests and commit messages since the last release, groups them into the six categories, drops the internal noise and drafts them in your house voice. A human then decides what is notable and checks that every breaking change is flagged.

That middle judgement is the whole game. A model has no way of knowing that a one line config change quietly alters a default for every customer on an old plan, while the 400 line refactor above it changes nothing anyone will notice. Notability is a product decision wearing an engineering costume. We wrote up the workflow, including how to codify a house style, in how to use AI to write changelog updates.

My honest take: the format was never the hard part. Teams do not have bad changelogs because they picked the wrong headings. They have bad changelogs because writing one is the last task before a release ships and the first task to get cut.

What to do next

Open your last three releases and read the entries as someone who did not build them. If a line does not tell that person what changed and whether to act, rewrite it using verb, object, consequence, then add an Unreleased section so the next one gets written at merge time instead of on release day.

If the entries also need somewhere to live, Sleekplan works as a changelog tool with an in-app widget and email digests: write the post, pick a category, set a release time, and subscribers get the digest while the widget shows an unread badge until they open it. Because it sits in the same workspace as the feedback board, a request whose status flips to Released publishes to the changelog on its own, so the people who asked for the feature hear that it landed.

FAQ

What should a changelog entry include?

One line per change, naming the feature in the words your users use, plus a consequence clause when the reader has to do something. Breaking changes, removals and changed defaults always need that clause. Skip internal refactors that no user can observe.

How often should you publish a changelog?

Every release, without exceptions. The mechanism that makes this sustainable is an Unreleased section at the top of the file: contributors add a line as part of the change itself, so at release time you rename a heading instead of reconstructing history. Teams that write the changelog after the fact are the teams whose changelogs eventually stop.

What should the changelog file be called?

Call it CHANGELOG.md, in the root of the repository. Keep a Changelog notes that some projects use HISTORY, NEWS or RELEASES, then asks the obvious question: why make it harder for your end users to find notable changes? The uppercase convention exists so the file sits next to README where people already look.