How to Write a Changelog: Format, Examples, and Templates
How to create and maintain a changelog for your project. Covers the Keep a Changelog format, semantic versioning, automation, and ready-to-use templates.
Last updated: February 28, 2026
A changelog is a file that lists notable changes for each version of a project. It helps users and contributors understand what changed, why it changed, and when. The standard format is a markdown file named CHANGELOG.md at the root of your repository.
The Keep a Changelog Format
The most widely adopted format is Keep a Changelog, which organizes entries by version and change type.
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com),and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased]
### Added- New API endpoint for bulk operations
## [1.2.0] - 2026-03-01
### Added- Custom domain support for Pro users- Dark mode toggle in the editor
### Changed- Improved PDF export rendering speed
### Fixed- Links with parentheses in URLs now render correctly- Fixed timeout on large file uploads
## [1.1.0] - 2026-02-15
### Added- Markdown table support in the editor- CLI flag for custom output directory
### Deprecated- The `--legacy` flag will be removed in v2.0
### Removed- Dropped support for Node.js 16
### Security- Updated dependencies to patch CVE-2026-1234Change Types
Keep a Changelog defines six categories:
| Type | When to Use |
|---|---|
| Added | New features or functionality |
| Changed | Modifications to existing features |
| Deprecated | Features that will be removed in a future version |
| Removed | Features that were removed in this version |
| Fixed | Bug fixes |
| Security | Vulnerability patches and security improvements |
Use only the categories that apply to each release. Skip empty categories.
Writing Good Changelog Entries
Be specific. Describe what changed, not that something changed:
<!-- Vague -->- Improved performance
<!-- Specific -->- Reduced API response time from 800ms to 120ms for list endpointsWrite for users, not developers. A changelog is for people who use your software. Internal refactors that do not affect behavior do not belong here.
<!-- Internal detail users don't care about -->- Refactored auth module to use strategy pattern
<!-- User-facing change -->- Login now supports Google and GitHub OAuthLink to relevant issues or PRs when helpful:
- Fixed file upload timeout on files over 10MB ([#142](https://github.com/user/repo/issues/142))Use present tense or past tense consistently. Both conventions are common. Pick one and stick with it:
<!-- Present tense -->- Add custom domain support- Fix timeout on large uploads
<!-- Past tense -->- Added custom domain support- Fixed timeout on large uploadsSemantic Versioning and Changelogs
Changelogs pair well with Semantic Versioning (SemVer):
| Version Change | When | Example |
|---|---|---|
| Major (X.0.0) | Breaking changes | Removing an API endpoint, changing default behavior |
| Minor (0.X.0) | New features (backwards-compatible) | Adding a new CLI flag, new API endpoint |
| Patch (0.0.X) | Bug fixes and security patches | Fixing a rendering bug, patching a vulnerability |
The changelog makes SemVer meaningful. Users can look at the version number to understand the scope of changes, then read the changelog for details.
The Unreleased Section
Keep an [Unreleased] section at the top for changes that have been merged but not yet released:
## [Unreleased]
### Added- Webhook support for publish events
### Fixed- Editor cursor position reset on saveWhen you cut a release, move the unreleased items under a new version heading with today’s date and start a fresh [Unreleased] section.
Changelog vs Release Notes
| Aspect | Changelog | Release Notes |
|---|---|---|
| Audience | Developers, contributors | End users, broader audience |
| Tone | Technical, concise | Marketing-friendly, may include screenshots |
| Format | Bullet points by category | Narrative with highlights |
| Location | CHANGELOG.md in repo | GitHub Releases, blog post, email |
| Scope | Every notable change | Highlights and key changes |
Many teams maintain both: a changelog as the technical record and release notes as the user-facing announcement. For more on this distinction, see Release Notes vs Changelog.
Automating Changelogs
Several tools can generate changelogs from Git commits or pull requests:
| Tool | Approach |
|---|---|
| Conventional Commits | Standardized commit messages (feat:, fix:, chore:) parsed by tools |
| changesets | PR-level change descriptions, merged into changelog on release |
| standard-version | Bumps version and generates changelog from conventional commits |
| release-please | Google’s tool for automated releases and changelogs from conventional commits |
| GitHub Releases | Auto-generates release notes from PR titles |
Conventional Commits
The convention formats commit messages as:
type(scope): description
feat(api): add bulk delete endpointfix(editor): resolve cursor jump on pastedocs(readme): update installation instructionsTools parse these into changelog categories: feat maps to “Added”, fix maps to “Fixed”, and so on.
Automation helps, but review the output before publishing. Auto-generated entries often need editing for clarity and completeness.
Templates
Basic Changelog
# Changelog
## [Unreleased]
## [1.0.0] - 2026-03-04
### Added- Initial release- Core publishing functionality- CLI with `publish` and `list` commands- Free and Pro tiersDetailed Changelog
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com),and this project adheres to [Semantic Versioning](https://semver.org).
## [Unreleased]
### Added- Webhook notifications for publish events
## [2.1.0] - 2026-03-01
### Added- Custom domain support ([docs](/docs/guides/custom-domains))- Bulk publish command: `mdtolink publish *.md`
### Changed- Default expiry for free tier increased from 3 to 7 days
### Fixed- PDF export now preserves syntax highlighting colors- Fixed 404 on slugs containing periods
## [2.0.0] - 2026-02-01
### Changed- **Breaking:** API authentication now requires Bearer tokens (API keys still work but are deprecated)
### Removed- Dropped support for Node.js 16
### Security- Updated marked to v15.0.0 (XSS fix)Minimal Changelog (For Small Projects)
# Changelog
## 1.2.0 (2026-03-04)- Add dark mode- Fix image rendering in tables
## 1.1.0 (2026-02-15)- Add table support- Improve CLI output formatting
## 1.0.0 (2026-01-01)- Initial releaseFAQ
Where should the changelog file live?
Put CHANGELOG.md in the root of your repository. This is the standard location. GitHub, GitLab, and most tools look for it there.
How is a changelog different from git log?
A git log contains every commit, including typo fixes, merge commits, and internal refactors. A changelog is curated: it lists only changes that matter to users, grouped by version and category.
Should I include internal changes in the changelog?
No. Refactors, dependency updates (unless security-related), and code cleanup that do not affect users should be left out. The changelog is for user-facing changes.
How often should I update the changelog?
Update it with every pull request that introduces a notable change. Use the [Unreleased] section to collect changes between releases. This avoids a last-minute scramble when cutting a release.
Publish Your Changelog
Write your changelog in markdown, then share it with your team or users. The MDtoLink editor lets you preview your changelog in real time. When it’s ready, publish it to a shareable URL with one click using mdtolink publish CHANGELOG.md.
For the full markdown syntax reference, see the markdown cheat sheet. For tips on document structure, see the headings guide.
Founder, MDtoLink
David builds developer tools and writes about markdown workflows, documentation, and AI-assisted publishing.
Publish your markdown to a shareable URL
One command. Free to start. No credit card.