CHANGELOG.md template (Keep a Changelog)
Make your CHANGELOG.md
Fill these in and the whole file updates. Nothing is sent anywhere, and there is nothing to sign up for.
# Changelog All notable changes to this project are documented here. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] ### Added - Anything already merged but not yet released goes here, so the release notes write themselves on the day. ## [2.1.0]: 2026-07-14 ### Added - Export to PDF from the command line (`--export pdf`). - `--quiet` flag for use in scripts. ### Changed - Config files are now resolved from the project root rather than the working directory. Running from a subdirectory picks up the same config as running from the root. ### Deprecated - `--legacy-parser`. It still works and will be removed in 3.0. ### Fixed - Files over 2 GB no longer fail with a misleading "permission denied". - Windows paths containing spaces are handled correctly. ## [2.0.0]: 2026-05-02 ### Removed - **Breaking:** dropped Node 18. The minimum is now Node 20. - **Breaking:** `parse()` no longer accepts a callback. Use the returned promise. ### Security - Updated a transitive dependency with a prototype-pollution advisory ([CVE-2026-1234](https://example.com)). ## [1.4.2]: 2026-03-11 ### Fixed - Restored the exit code on parse failure, which 1.4.1 changed by accident. [Unreleased]: https://github.com/you/project/compare/v2.1.0...HEAD [2.1.0]: https://github.com/you/project/compare/v2.0.0...v2.1.0 [2.0.0]: https://github.com/you/project/compare/v1.4.2...v2.0.0 [1.4.2]: https://github.com/you/project/releases/tag/v1.4.2
Visual
A changelog is written for one person: someone on an older version deciding whether upgrading is worth the risk. Every convention below follows from that.
The six categories
Keep a Changelog fixes the vocabulary so readers do not have to learn yours:
- Added: new features.
- Changed: changes to existing behavior.
- Deprecated: still works, going away, say when.
- Removed: gone. Breaking, by definition.
- Fixed: bug fixes.
- Security: vulnerabilities addressed. Always its own heading, never buried under Fixed.
The value is entirely in the consistency. Someone auditing a dependency for breaking changes reads Removed and Changed and skips the rest, and can only do that if every project uses the words the same way.
Unreleased is where entries accumulate
Add the entry in the pull request that makes the change, under ## [Unreleased].
On release day, rename that heading to the version and date, and open a fresh
empty Unreleased above it. Release notes stop being a task.
Write for the upgrader, not the committer
### Changed
- Config files are now resolved from the project root rather than the
working directory. Running from a subdirectory picks up the same
config as running from the root.
That entry says what changed and what the reader will observe. Compare
refactor: move config resolution to root - accurate, and useless to someone
deciding whether to upgrade.
Breaking changes earn the word
### Removed
- **Breaking:** `parse()` no longer accepts a callback. Use the returned
promise.
Lead with Breaking, name the replacement in the same entry, and bump the major version. A reader should never have to open your issue tracker to find out what to do instead.
The links at the bottom
[Unreleased]: https://github.com/you/project/compare/v2.1.0...HEAD
[2.1.0]: https://github.com/you/project/compare/v2.0.0...v2.1.0
Reference-style definitions that make every version heading a link to the diff. Update the top one on each release and add a line: it takes seconds and turns the changelog into a navigable history rather than a flat list.
Common questions
- What are the standard change categories?
- Keep a Changelog defines six: Added, Changed, Deprecated, Removed, Fixed and Security. Sticking to them means a reader scanning for breaking changes knows exactly which two headings to look under, in any project that follows the convention.
- What is the Unreleased section for?
- Collecting entries as they merge, so the release notes are already written on release day. When you cut the version, the Unreleased heading becomes the version heading and a fresh empty one goes above it.
- Should a changelog be generated from commit messages?
- Generated lists are commit logs with extra steps. A changelog is written for the person deciding whether to upgrade, and most commits do not affect that decision. Write the entries by hand; there are fewer of them than you expect.
- How do I mark a breaking change?
- Under Removed or Changed, with the word "Breaking" leading the entry, and bump the major version. Say what to do instead in the same line: an entry that reports a break without naming the replacement just moves the work to your issue tracker.
- What are the link definitions at the bottom?
- Markdown reference links, which is what makes each version heading clickable. They point at your host's compare view, so a reader can see the actual diff between two releases without leaving the changelog.
- Newest at the top or the bottom?
- Newest at the top, always. Almost everyone opening a changelog is asking "what changed since the version I have", and that answer should not require scrolling past five years of history.
Sources
- Keep a Changelog 1.1.0the convention this template follows