Changelog Maintenance
Keeping a human-readable record of what changed, for whom, and why.
Overview
A changelog is a curated, human-readable record of notable changes per release, distinct from raw commit history. "Keep a Changelog" (Olivier Lacan, 2014) standardised the format: sections for Added, Changed, Deprecated, Removed, Fixed, Security, ordered by version in descending order. Conventional Commits enables automated changelog generation via standard-version or semantic-release.
Origin
Changelogs predate version control; Unix distributions maintained NEWS files. Semantic Versioning (Tom Preston-Werner, 2013) gave versioning meaning that changelogs could map to. "Keep a Changelog" (keepachangelog.com, 2014) standardised the human-readable format. Conventional Commits (2019) enabled automated generation, closing the loop between commit messages and release notes.
Examples
Automated changelog via semantic-release
// .releaserc.json
// {
// "branches": ["main"],
// "plugins": [
// "@semantic-release/commit-analyzer",
// "@semantic-release/release-notes-generator",
// ["@semantic-release/changelog", {
// "changelogFile": "CHANGELOG.md"
// }],
// ["@semantic-release/npm", { "npmPublish": false }],
// ["@semantic-release/github", {
// "assets": [{"path": "dist/*.tgz", "label": "Distribution"}]
// }],
// ["@semantic-release/git", {
// "assets": ["CHANGELOG.md", "package.json"],
// "message": "chore(release): \${nextRelease.version} [skip ci]"
// }]
// ]
// }
// Commit type to version bump mapping:
// feat: bumps MINOR (1.0.0 -> 1.1.0)
// fix: bumps PATCH (1.0.0 -> 1.0.1)
// BREAKING CHANGE: bumps MAJOR (1.0.0 -> 2.0.0)
// chore/docs/style: no bumpsemantic-release runs in CI on every merge to main, analyses commits since the last release, determines the version bump, generates the changelog, publishes to npm (if configured), creates a GitHub Release, and commits the updated CHANGELOG.md. Zero manual steps.
Manual CHANGELOG.md format following Keep a Changelog
# Excerpt from CHANGELOG.md following keepachangelog.com format
# Changelog
# All notable changes to this project will be documented in this file.
# Format is based on Keep a Changelog (keepachangelog.com/en/1.1.0/)
# and this project adheres to Semantic Versioning (semver.org/spec/v2.0.0.html).
# ## [Unreleased]
# ### Added
# - Bulk order cancellation endpoint (POST /api/v1/orders/bulk-cancel)
# - Rate limiting headers (X-RateLimit-Limit, X-RateLimit-Remaining)
# ## [2.4.0] - 2025-11-15
# ### Added
# - Stripe payment method management API
# - Customer portal link generation (Stripe Billing Portal)
# ### Changed
# - Upgraded Stripe SDK from 10.x to 12.x; payment intent flow updated
# ### Deprecated
# - GET /api/v1/charges endpoint; use /api/v1/payment-intents instead
# ### Security
# - Fixed IDOR vulnerability on invoice download endpoint (CVE-2025-XXXX)
# ## [2.3.1] - 2025-10-02
# ### Fixed
# - Tax calculation rounding error for orders with multiple discount codesThe Unreleased section collects changes before the next release. When releasing, the section becomes [2.5.0] - YYYY-MM-DD. Security section always appears even for minor releases when CVEs are addressed; it signals to downstream consumers to upgrade immediately.
Use Cases
- 01Library and package consumers who need to assess the impact of upgrading without reading every commit
- 02Security operations teams who monitor changelogs for CVE disclosures and plan emergency upgrades
- 03Release communication: the GitHub Release body is populated from the changelog, giving users release notes without navigating commit history
- 04Legal and compliance: changelogs provide an audit trail of when security fixes were applied, necessary for SOC 2 and ISO 27001 evidence
When Not to Use
- //Do not maintain a manual CHANGELOG.md for projects using semantic-release; the automated version is more accurate and eliminates the commit-to-changelog synchronisation problem
- //Do not include every commit in the changelog; changelogs are for consumers of the library, not for internal development tracking. Exclude chore, style, and refactor entries
- //Do not use raw git log output as a changelog; unformatted commit messages do not give consumers the context they need to assess upgrade risk
Technical Notes
- standard-version (deprecated as of 2023 in favour of release-please or semantic-release) generated changelogs from Conventional Commits; release-please (Google, 2020) is the maintained replacement with native GitHub Actions integration
- Changelog links in the footer of CHANGELOG.md ([2.4.0]: https://github.com/org/repo/compare/v2.3.1...v2.4.0) allow readers to diff the exact commits included in a release
- GitHub Releases and npm package changelogs are separate; a common mistake is publishing to npm without updating the GitHub Release notes. semantic-release handles both atomically
- conventional-changelog-cli can retroactively generate a CHANGELOG.md from an existing repository's Conventional Commits history, enabling adoption without losing historical context