---
title: "Markdown changelog template: versions people can read"
slug: markdown-changelog-template
excerpt: "Keep a categorized project history in CHANGELOG.md, with Unreleased work, dated versions and explicit breaking changes."
quickAnswer: "Put CHANGELOG.md in the project's main folder. Begin with Unreleased, then list dated versions newest first, grouping entries under Added, Changed, Fixed and Removed."
keyTakeaways:
  - "Reserve Unreleased for completed changes that do not yet belong to a dated version."
  - "Arrange dated version entries from newest to oldest."
  - "Group additions, behavior changes, repairs and removals under distinct headings."
  - "Mark a breaking change explicitly and describe the action an existing user needs to take."
  - "Keep the history in one CHANGELOG.md as the project develops."
publishedDate: 2026-10-23
dateModified: 2026-10-23
author: Bobby Huang
cluster: A
role: post
status: published
faq:
  - q: "What belongs under Unreleased?"
    a: "Completed changes waiting for a dated version belong there. Proposed work belongs elsewhere."
  - q: "Should every small internal edit appear in a changelog?"
    a: "Write entries for changes that affect someone using the project. Internal edits with no user effect need no entry."
  - q: "How do I describe a breaking change?"
    a: "Begin the entry with Breaking change, identify the old and new behavior, and state what existing users need to do."
related:
  - markdown-readme-template
  - markdown-status-report-template
---

A Markdown changelog template gives project users a written history organized by version. Each entry describes something they can now do, something that behaves differently, a repaired fault or something that no longer exists. The file answers a practical question: what changed between the version I know and this one?

This page includes a blank starting pattern and a fictional Doe Holdings example. If the filename extension is unfamiliar, read [what an .md file is](what-is-a-md-file.md) before filling in the text.

## Write history for project users

Choose changes by their effect on someone using the project. A renamed setting belongs in the history because an existing user may need to act. Renaming an internal variable without changing behavior does not need an entry.

Describe the visible difference rather than the work involved. "Fixed item totals that omitted the last row" names a fault and its repair. "Updated calculation code" leaves the user to work out whether their totals were affected.

Keep each bullet about one change. Two unrelated repairs get two bullets, even if the same person made both edits. Use the project's own terms for features and settings so users can connect the entry to what they use.

## An empty changelog template

Name the file `CHANGELOG.md`. Replace the descriptive placeholders below with your project's details. The placeholder version and date show where each value belongs; they are not a numbering policy.

```markdown
# Changelog: [Doe project name]

## Unreleased

### Added

- [Describe a completed new capability awaiting a dated version.]

### Changed

- [Describe an existing behavior that now works differently.]

### Fixed

- [Describe the fault and the behavior after its repair.]

### Removed

- [Name the capability that is no longer part of the project.]

## [Version number] - [YYYY-MM-DD]

### Added

- [Name a new capability in this version.]

### Changed

- Breaking change: [Old behavior] becomes [new behavior]. [State the action existing users need to take.]

### Fixed

- [Name a repaired fault in this version.]

### Removed

- [Name a removed capability and any replacement.]
```

Leave `Unreleased` above every dated version. It holds completed work awaiting a version entry, rather than ideas or unfinished work. When that work becomes a dated version, move its bullets beneath the new version heading and leave Unreleased at the top for the next changes.

Put the newest dated version immediately below Unreleased. Older versions follow beneath it. Use `YYYY-MM-DD` for dates, alongside the project's existing version labels. The date records when that version became usable by its intended users, rather than the day someone happened to edit the history.

The four group headings distinguish kinds of change:

- **Added** describes a capability absent from earlier versions.
- **Changed** describes different behavior in a capability that remains.
- **Fixed** describes a fault that no longer occurs.
- **Removed** identifies something users can no longer use.

Drop an empty group from a dated entry. An absent Fixed heading means that version has no repair entry; an empty heading leaves the reason unclear. The starting block includes all four groups to show their positions, so replace or omit its prompts before treating it as history.

## A fictional Doe Holdings changelog

Doe Holdings item counter is an invented project that counts items from a text file. Jane Doe keeps its history. All capabilities, version numbers and dates in this example are fictional.

```markdown
# Changelog: Doe Holdings item counter

Jane Doe keeps this project history.

## Unreleased

### Added

- Added an option to display item counts by category.

### Fixed

- Fixed the total for files whose final row has no ending line break.

## 2.0.0 - 2026-10-20

### Added

- Added support for item labels containing spaces.

### Changed

- Breaking change: Each item row now uses a colon between its label and count instead of a comma. Replace the comma separator in existing input files with a colon before using this version.

### Fixed

- Fixed a failure when an item label contains an accented letter.

### Removed

- Removed automatic use of counts.txt when no input file is named. Name the input file explicitly on each run.

## 1.1.0 - 2026-10-06

### Added

- Added a summary showing the number of item rows counted.

### Fixed

- Fixed totals that counted the first item twice.
```

Jane Doe's Unreleased repair stays separate from version 2.0.0. A user reading that dated entry should not assume the repair is part of it. Once the pending work receives its own version, its bullets move into that entry together.

The 2.0.0 entry also distinguishes a changed input convention from a removed default. Both require user action, but they affect different parts of a run. Neither action is hidden behind a general phrase such as "updated input handling."

## Make breaking changes explicit

A breaking change prevents an existing way of using the project from continuing unchanged. Put the words **Breaking change** at the beginning of its bullet, followed by the behavior being replaced, the new behavior and the required adjustment.

For the fictional counter, the separator changes from a comma to a colon. The bullet names both characters and tells users to change existing input files before using that version. A statement such as "new input format" would leave those details unresolved.

Use the category that matches the change. A different input convention belongs under Changed; a capability that disappears belongs under Removed. Add the breaking-change label in either category when existing usage requires an adjustment. If there is no replacement for a removed capability, say so directly rather than suggesting a substitute that does not exist.

Avoid repeating the full migration procedure inside the history. Describe the required adjustment so existing users can judge whether they need to act. Longer project instructions can carry the detailed procedure separately.

For a problem that persists after the adjustment, use the [troubleshooting guide template](markdown-troubleshooting-guide-template.md) to pair each symptom with a check, its result and the next action.

## Keep CHANGELOG.md with the project

Store `CHANGELOG.md` directly within the project's main folder, next to its README.md. For the example, the path is `doe-item-counter/CHANGELOG.md`. Keep that filename through successive versions so the history accumulates in one place. For other documents in the folder, the [Markdown filename guide](markdown-file-naming.md) covers choosing consistent names.

Add an Unreleased bullet when a user-facing change is complete, while its effect is still fresh. Before giving those bullets a dated heading, compare their wording with the actual behavior of that version. Exclude unfinished work and remove any entry for a change that was abandoned before reaching a dated version.

Preserve earlier dated entries when adding a new one. If an old entry contains a factual error, correct its wording without moving the change into a different version. The history needs to retain the distinction between when a behavior changed and when its description was corrected.

Separate headings from their bullets with an empty line; separate paragraphs that way too. For the effect of paragraph spacing, see [Markdown paragraph gaps](markdown-paragraphs-blank-lines.md). Read the finished history in order from Unreleased through the newest dated entry to catch misplaced bullets or a missing user action.

## Where Sashmark fits

Changelog wording deserves a reading pass after an AI agent has edited the project's Markdown files. For that desktop reading and editing work, Sashmark is being built around Markdown from AI agents. Development is still under way, with reading the history and revising its wording as the intended role here.
