Creating Changelog Entries
Overview
Towncrier assembles the changelog from per-change "fragment" files — one small file per change, collected and rendered at release time. This skill applies to any project that uses Towncrier. Every issue fix or new feature should ship with a fragment, written short and user-facing: describe what changed, not how it was implemented.
Core rule: always create fragments with towncrier create, never hand-write them. The command derives the location and naming from the Towncrier config and places the fragment correctly from anywhere in the repo.
When to Use
- You fixed a bug or added a feature and are about to commit or open a PR.
- You're asked to "add a changelog entry", "create a news fragment", or "run towncrier".
- A PR checklist or CI flags a missing changelog entry.
When NOT to use: the project doesn't use Towncrier; pure internal refactors with no user-facing or maintenance impact; and changes the team has explicitly decided don't warrant an entry. (The boundary for internal maintenance is below — don't add a housekeeping fragment by default.)
Exception — unreleased features need no fragment. A fix or follow-up to a feature that has not
shipped in any release is not user-observable: the feature's own added fragment already covers
everything a user will ever see, and a fixed entry for something never released is noise.
Exception — a stacked PR series carries one fragment, on the top PR. Intermediate PRs in a stack
skip the fragment: per-PR fragments collide on the same issue-number stem and describe a surface the
later PRs change again. State the deliberate skip in the intermediate PR's checklist instead of
leaving the box silently unticked.
housekeeping is not a catch-all. It covers internal work a user could still notice — a
build, tooling, or CI change. A change with no user-facing effect at all (an internal
type annotation, a behavior-preserving refactor, a lint or type-checker config cleanup that touches
no source code, cleanup of internal docs or spec scaffolding) gets no fragment. When it's unclear
whether a change is user-facing, ask instead of adding one by default.
Quick Reference
uv run towncrier create -c "content of changelog entry" ${ISSUE}.${TYPE}.md
These commands use uv run, which runs the project's pinned Towncrier and is the convention across these Python projects. If your project doesn't use uv, drop the prefix (towncrier create ...) or use its runner (e.g. poetry run towncrier ...).
- ISSUE — issue ID, or
+ when no issue exists (e.g. +pnpm-workspaces). With an issue, the stem is the bare number and nothing else: Towncrier renders the whole stem through issue_format, so 1234-short-slug.fixed.md links to issue 1234-short-slug — a 404. Only orphan (+) fragments take a descriptive slug. Verify with towncrier build --draft when unsure.
- TYPE — one of the change types below.
| Type | Use For |
|---|
added | New features |
changed | Changes in existing functionality |
deprecated | Soon-to-be removed features |
removed | Now removed features |
fixed | Bug fixes |
security | Security vulnerabilities |
housekeeping | Internal maintenance and tooling (build, CI, dev scripts) |
The available types come from the project's Towncrier config ([tool.towncrier]); the set above is the common default. How a project classifies some changes is project-specific — dependency-version bumps in particular land under changed in some projects and housekeeping in others, so follow the project's changelog guide rather than assuming.
Fragment Location
Fragments live in the directory Towncrier is configured to use (its directory setting — commonly the repo-root changelog/ or newsfragments/). towncrier create puts them there automatically — don't move them or hand-place them.
In a monorepo, they do not belong in a sub-package directory such as backend/changelog/ or frontend/changelog/. A fragment found there was hand-written in the wrong place and must move to the configured directory.
Exception: a nested package with its own Towncrier config (e.g. a submodule like Infrahub's python_sdk) keeps its own fragments in that package's configured directory — those stay put and must not be moved to the root.
Writing Good Messages
- Write from the user's perspective.
- Focus on what changed, not how.
- Use past tense ("Fixed", "Added", "Removed").
- Keep it concise — one sentence.
- Avoid technical jargon.
Examples
# Bug fix for issue #1234
uv run towncrier create -c "Fixed sidebar collapse issue" 1234.fixed.md
# New feature for issue #7549
uv run towncrier create -c "Added breadcrumb navigation for hierarchical schemas" 7549.added.md
# Housekeeping without an issue
uv run towncrier create -c "Migrated the frontend build to pnpm workspaces" +pnpm-workspaces.housekeeping.md
Common Mistakes
- Getting the filename shape wrong. It is
<issue-or-+slug>.<type>.md; the type segment is
required, and a file without one is not picked up. Everything before it is either a GitHub issue
number or a +-prefixed slug, because issue_format turns a bare name straight into a GitHub
issue URL: IFC-2747.fixed.md ships a link to an issue that does not exist. The + marks the
entry as an orphan and suppresses the link, so +ifc-2546-lorem-ipsum.changed.md is valid — but
the ticket ID never appears in the output, so spend the slug on a description instead. Use a bare
issue number only when the release note should link that GitHub issue; a change merely related to
an issue — a follow-up, a separate fix found along the way — takes an orphan +slug, and the slug
carries no metadata, so there is nothing to "fix" in an orphan name that lacks an issue ID.
- Hand-writing the fragment file. Use
towncrier create so the name and location are correct.
- Placing it in a sub-package directory (e.g.
backend/changelog/) instead of the configured fragments directory.
- Describing the implementation. "Refactored the auth-token cache layer" → instead say what the user sees: "Fixed users being unexpectedly logged out".
- Wrong tense or multiple sentences. One past-tense sentence.
- Duplicating an existing fragment. On a feature branch spanning multiple PRs, list the fragments directory first — numbered (
NNNN.type.md) and +-prefixed fragments all render into the changelog. If a fragment already describes the same user-visible change, extend or reconcile it instead of adding an overlapping one.
See Also
- Towncrier documentation — fragment types, configuration, and CLI options.
- Keep a Changelog — changelog best practices.
- Your project's contributing or changelog guide for project-specific conventions (in Infrahub:
docs/docs/development/changelog.mdx).