Styling Guides

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 bump

semantic-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 codes

The 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