Software Release Changelog & Notes Markdown Table Template
A changelog exists so that someone deciding whether to upgrade can answer three questions quickly: what changed since the version I run, will anything break, and is there a security fix I need now. The readers are users of a library pinning dependency versions, operators planning a maintenance window, and support staff matching a bug report to the release that fixed it. None of them want commit messages; they want curated, human-written notes.
Edit This Template
Edit cells, add rows, or sort — the Markdown updates livePaste cells from Excel or Google Sheets into the first header to replace the table · Tab / Enter / arrows move · Shift+F10 opens row & column actions
When to Use This Table
The table in this template is best used as a release index: one row per version at the top of a CHANGELOG.md, in a README, or on a docs landing page, summarising each release and flagging breaking ones. The detailed notes underneath usually follow the Keep a Changelog convention: newest release first, an Unreleased section at the top, ISO 8601 dates, and changes grouped under Added, Changed, Deprecated, Removed, Fixed, and Security.
Version numbers carry meaning when you follow Semantic Versioning: a MAJOR bump for incompatible API changes, MINOR for backward-compatible features, PATCH for backward-compatible fixes. A good table makes the version, the date, and the breaking-change flag agree with each other — a release marked “Breaking: Yes” on a minor bump tells readers either the flag or the number is wrong, and they will not know which.
What Goes in Each Column
| Column | Alignment | What to put here |
|---|---|---|
| Version | center :---: | The release version in backticks, matching the Git tag. SemVer itself defines the number without a prefix (2.1.0); a v on tags is a common convention, so pick one style and use it everywhere. Centered. Link it to the release page or compare view if you can. |
| Release Date | center :---: | ISO 8601 YYYY-MM-DD, the format Keep a Changelog recommends because it sorts correctly and is unambiguous across locales. Use the date the release was published, not the date the branch was cut. Centered so dates line up. |
| Classification | center :---: | Pick one axis and stick to it. Either release type (Major, Minor, Patch) derived from the version number, or the dominant change type (Added, Fixed, Security). The template mixes both, which makes “Feature” and “Patch” look like alternatives when they are not. |
| Highlights & Resolved Issues | left :--- | One or two lines on what a user would notice, starting with a verb in past tense. Use backticks for affected functions or flags (parseCSV()) and link issue numbers. Left-aligned. Leave exhaustive lists for the detailed section below the table. |
| Breaking Changes | center :---: | A clear None or a short description with a link to migration notes — “Yes (API updated)” leaves readers searching. Centered when values are short. Under SemVer, any Yes after 1.0.0 should coincide with a MAJOR version bump. |
How to Fill It In
- 1List the tags you are documenting with
git tag --sort=-creatordateand get each publish date from the release page orgit log -1 --format=%cs <tag>. - 2For each release, read the merged pull requests between it and the previous tag (
git log prev..tag --merges) and write the user-facing changes in your own words. If you use Conventional Commits,featandfixprefixes give you a first draft. - 3Classify every change under Added, Changed, Deprecated, Removed, Fixed, or Security, and check the version bump matches: anything breaking means MAJOR, new features MINOR, fixes only PATCH.
- 4Write the breaking-change cell last, with a link to the upgrade guide. For security fixes, reference the CVE or advisory ID once it is public.
- 5Order the table newest first, keep an
Unreleasedsection in the detailed notes, and add the changelog update to the release checklist so it ships with the tag rather than afterwards.
Ready-to-Paste Variations
Change-per-row log in Keep a Changelog categories
One row per change instead of per release, using the six standard categories. Sorts and filters well, and maps directly onto the sections of a CHANGELOG.md.
| Version | Date | Type | Change |
| :---: | :---: | :--- | :--- |
| Unreleased | — | Deprecated | `toTSV()` alias; use `toDelimited("\t")` |
| `2.1.0` | 2025-03-01 | Added | Streaming CSV parser for files over 50 MB |
| `2.0.0` | 2025-01-15 | Removed | Legacy regex parser `parseLegacy()` |
| `1.9.4` | 2024-12-08 | Fixed | Escaped pipes inside code spans no longer split cells |
| `1.9.3` | 2024-11-20 | Security | Prototype pollution in JSON import |Upgrade guide for breaking releases
Only MAJOR releases, each with what breaks and what to change. Link to it from the Breaking Changes column of the main table.
| From → To | What breaks | What to do |
| :--- | :--- | :--- |
| `1.x` → `2.0.0` | `parse()` returns an AST instead of a string array | Call `toRows(parse(input))` for the old shape |
| `1.x` → `2.0.0` | Node 16 support dropped | Upgrade to a supported Node LTS release |
| `0.x` → `1.0.0` | Default delimiter changed from `;` to `,` | Pass `{ delimiter: ";" }` explicitly |Common Mistakes
Pasting
git logoutput as the changelog.Commit messages are written for maintainers. Curate the entries for users: group them by type, drop refactors and CI tweaks, and describe effects rather than implementation.
Shipping a breaking change in a minor or patch release.
Under SemVer, incompatible API changes after
1.0.0require a MAJOR bump. If one slipped out, release a patch that restores compatibility and note the incident in the changelog.Using locale dates like
03/01/2025.Use
2025-03-01. Readers in the US and Europe interpret slash dates differently, and ISO dates sort correctly as plain text.Hiding security fixes under “Bug fixes”.
Give them their own Security entry so people scanning for urgent upgrades find them. Reference the advisory or CVE ID once it has been disclosed.
Related Markdown Table Templates
Browse all 50 templatesConventional Commits & Semantic Releases
Conventional Commit specifications mapping commit type prefixes to SemVer release impacts, changelog categories, and example formats.
Git Workflow & Branching Governance
Define branching conventions, source bases, pull request targets, required approval reviews, and CI automation gates.
Project Roadmap & Milestones
Quarterly roadmap tracking high-level initiatives, target milestones, delivery quarters, status indicators, and engineering leads.
Software Release Changelog & Notes: Frequently Asked Questions
Should a changelog be a table or a list?
The detailed changelog reads better as headed lists per release, which is the Keep a Changelog format. A table works well as the summary index above it, or in a README, where readers want to scan versions, dates, and breaking flags at a glance.
Is “v1.2.3” a valid semantic version?
Strictly, no — the SemVer spec says the version is 1.2.3 and the v is not part of it. Prefixing Git tags with v is extremely common and fine; just be consistent between tags, the table, and package metadata.
What goes in the Unreleased section?
Changes merged to the main branch but not yet tagged. Keeping it current means a release is just renaming the section to the new version and date, and it lets users see what is coming before it ships.
How far back should the table go?
Keep every release in the detailed changelog, since people upgrade from old versions. In a README summary table, the last five to ten releases plus every MAJOR release is usually enough, with a link to the full file.