FOSS Resources

How to Maintain a Changelog

A changelog is a maintained, cumulative record of meaningful project changes, not a raw commit feed.

A changelog is a cumulative, human-readable record of meaningful changes in a project. It helps users, contributors, package maintainers, and downstream teams understand what changed across versions without reading every commit.

A useful changelog is not generated noise. It groups changes by version and type, keeps an unreleased section for work in progress, and records changes that matter to people using or maintaining the software.

Changelog and release notes have separate roles

Release notes explain one release in a user-facing narrative. A changelog preserves the structured history across releases. The two can link to each other, but they should not be identical.

The changelog is where a user can compare versions, see when a fix landed, confirm whether an API was removed, or understand which release introduced a change. Release notes can be more selective and explanatory.

If a project only has raw commits, users must infer importance from terse messages. A maintained changelog saves that effort and reduces repeated questions.

A maintainable structure

Keep a Changelog popularized a practical structure: an Unreleased section, version headings with dates, and change categories such as Added, Changed, Deprecated, Removed, Fixed, and Security.

That pattern works because it answers several questions quickly:

  • Which version included this change?
  • Was the change a feature, fix, removal, or security note?
  • Is unreleased work already known?
  • Which changes affect users rather than only maintainers?
  • Where can readers find the linked issue, pull request, or release?

The exact categories can be adapted, but consistency matters. If the same kind of change moves between categories every release, readers stop trusting the structure.

What belongs in each category

Use categories to clarify impact:

CategoryUse whenExampleAvoid
AddedNew user-visible behavior existsAdded CSV export for filtered reportsAdded internal helper class
ChangedExisting behavior is differentChanged default cache locationImproved stuff
DeprecatedFeature still exists but should be replacedDeprecated legacy config keyRemoving without warning
RemovedFeature, platform, API, or file is goneRemoved Python 3.8 supportHiding removals in fixes
FixedDefect is correctedFixed crash when importing empty filesFixed bugs
SecurityPublicly disclosed security-relevant changeUpdated parser after advisory linkUnverified vulnerability claims

Not every commit belongs. Refactors, dependency bumps, formatting, build-script cleanup, and test-only changes may belong only when they affect users, packagers, contributors, or security posture.

Work from an unreleased section

An unreleased section prevents maintainers from trying to reconstruct release history at the last minute. Add entries as meaningful changes merge, then move them under a version heading when the release is cut.

This habit improves accuracy. The author of a pull request usually knows whether the change is Added, Changed, Fixed, or Removed. Waiting until release day makes the changelog dependent on memory.

The unreleased section should still be edited before release. Combine duplicates, remove internal details, clarify user impact, and ensure breaking changes are obvious.

Automation needs human editing

Automation can collect merged pull requests, issue numbers, labels, contributors, and commit messages. It can help maintainers avoid missed entries. It should not replace editorial judgment.

Commit messages are written for maintainers, not always for users. Labels can be wrong. Pull request titles can be too technical or too vague. A generated list may also overemphasize internal work while hiding a migration risk.

Use automation as input, then edit for meaning. The changelog should tell users what changed, not merely prove that work happened.

Traceability without clutter

Links can make a changelog more useful, but too many links can turn it into a noisy index. Link entries when the issue, pull request, advisory, migration guide, or release page adds detail that a reader may need.

For a small fix, one clear sentence may be enough. For a breaking change, security note, format change, or removed platform, link to the deeper explanation. If a changelog entry contains only issue numbers, readers have to open every link to understand the release.

Traceability is strongest when the visible text still stands on its own. A reader should understand the change before deciding whether to open the link.

Corrections and historical accuracy

Sometimes old changelog entries need correction. A version date may be wrong, a change may have been categorized incorrectly, or a security note may need a safer public link after disclosure.

Correct factual errors directly, but avoid rewriting old entries merely to match a new writing style. The changelog is a historical record. Large retroactive rewrites can make it harder for users and downstream packagers to compare what was said at release time.

When a correction materially changes user understanding, note the correction near the affected entry or in the next release notes. Quietly fixing a typo is different from changing whether a release contained a breaking change.

Changelog hygiene

Changelogs become hard to use when they mix styles, skip dates, change category names, or bury breaking changes under small fixes. They also lose value when old entries are rewritten without reason.

Good hygiene includes:

  1. Keep version headings and dates consistent.
  2. Link versions to release tags when useful.
  3. Link issue or pull request numbers only when the title explains the change.
  4. Put breaking changes where readers will notice them.
  5. Keep security details aligned with official public disclosure.
  6. Preserve history unless correcting a factual error.

The expected outcome is a history that a user can scan before upgrading and a maintainer can maintain without heroic cleanup.

Before cutting a release

Before publishing a new version, review the changelog for:

  • entries in the right version section;
  • clear user-facing wording;
  • removed, deprecated, or breaking behavior;
  • security entries that match public advisories or project notes;
  • issue links that add context;
  • release date and version number consistency;
  • no raw commit dumps or duplicate entries.

A changelog does not need to be long. It needs to be accurate, consistent, and written for the people who must understand the release history.