semantic-release vs release-please vs Changesets (and git-cliff)
All four turn work you've already done into a version number and a changelog. They disagree on where the release decision lives: in commit messages, in a release pull request you merge, or in small change files contributors write. Here's how they differ, from each project's own documentation, and how to pick one.
Updated Last checked 7 min readOpen-source libraries and packages
The short answer
- semantic-release releases from CI on every qualifying merge: it reads commit messages, picks the version, generates notes and publishes. Writing a CHANGELOG.md file takes the extra
@semantic-release/changelogplugin. - release-please keeps a release pull request up to date; merging it updates CHANGELOG.md, tags the commit and creates the GitHub release. It doesn't publish to package managers.
- Changesets stores release intent in Markdown change files instead of commit messages, and is built with monorepos in mind.
- git-cliff generates the changelog from your git history, with parsers and a template you control.
- Whichever you pick, the output is a draft. Edit it before it ships.
The commands you'll actually run
One block per tool. semantic-release and release-please usually run in CI; Changesets and git-cliff also work from your terminal.
# semantic-release: runs in CI after every successful build on the release branch
npx semantic-release
# release-please: a GitHub Actions step keeps a release pull request open
# uses: googleapis/release-please-action@v4
# Changesets: describe the change, then version and publish
npx changeset # pick packages + bump type, write a summary
npx changeset version # consume change files, bump versions, write changelogs
npx changeset publish # publish to npm and create git tags
# git-cliff: generate the changelog only
git cliff --init # create cliff.toml
git cliff -o CHANGELOG.md
git cliff --unreleased # just the commits since the last tagEach tool needs one-time setup (a config file, CI permissions or a registry token). Follow its own docs for that; this is the day-to-day.
Free tool · no sign-up
Can a coding agent read your changelog?
Paste your repository, a GitHub release or a CHANGELOG.md link. The free converter shows every version, breaking change, migration step and deprecation it can extract, as JSON plus an llms.txt summary.
No AI and nothing stored. Or paste a CHANGELOG.md instead
01The short version
| semantic-release | release-please | Changesets | git-cliff | |
|---|---|---|---|---|
| Release decision | Automatic in CI | You merge a release PR | Change files in each PR | You run it |
| Next version from | Commit messages (Angular convention by default) | Conventional Commits | Bump types in change files | Conventional Commits or your own regex parsers |
| Writes CHANGELOG.md | With @semantic-release/changelog | Yes, in the release PR | Yes, changeset version | Yes, git cliff -o CHANGELOG.md |
| GitHub release | Yes (default @semantic-release/github plugin) | Yes, when the release PR merges | Git tags on publish | Feed its output to your own release step |
| Publishes packages | Yes: npm by default, other ecosystems via plugins | No | Yes, to npm | No |
| Monorepos | Not described in the core docs | Yes, with manifest config | Built for them | Per directory, with --include-path |
| License | MIT | Apache-2.0 | MIT | MIT or Apache-2.0 |
02semantic-release: fully automatic releases
semantic-release “automates the whole package release workflow including: determining the next version number, generating the release notes, and publishing the package.” It's “meant to be executed on the CI environment after every successful build on the release branch”, and releases only when the commits since the last release call for one.
- By default it uses the Angular commit conventions:
fix→ patch,feat→ minor, and aBREAKING CHANGE:footer → major. - The default plugins are
@semantic-release/commit-analyzer,release-notes-generator,npmandgithub. The notes land on the GitHub release; a CHANGELOG.md file needs@semantic-release/changelog, and committing it back needs@semantic-release/git. - Its FAQ “strongly” recommends against committing during a release, because it “adds significant additional complexity to your release process”. Many projects therefore keep notes on GitHub releases only.
- It runs on Node.js (a recent version; check its docs) but can release other kinds of projects through plugins.
A good fit when every merge to main should ship, nobody wants to decide when to release, and your commit messages are reliably conventional. See release notes from Conventional Commits for the commit format.
03release-please: a release pull request you merge
release-please “maintains Release PRs” that are “kept up-to-date as additional work is merged.” When you merge one, it updates your changelog file and language-specific files such as package.json, “tags the commit with the version number” and “creates a GitHub Release based on the tag”. It “does not handle publication to package managers”, so you add your own publish step to the same workflow.
- It assumes Conventional Commits:
fix:→ patch,feat:→ minor,feat!:orfix!:→ major. - Release types cover many ecosystems, including
node,python,java,go,rustandsimple(a version.txt and a CHANGELOG.md). - Before 1.0,
bump-minor-pre-majormakes breaking changes bump the minor version andbump-patch-for-minor-pre-majormakes features bump the patch. - Monorepos use a manifest:
release-please-config.jsonplus.release-please-manifest.json. - To force a version, put
Release-As: x.x.xin a commit body. To fix a merged pull request's changelog line, add aBEGIN_COMMIT_OVERRIDE…END_COMMIT_OVERRIDEsection to its description (this doesn't work with plain merges).
A good fit when a person should decide when to release, you want to review the changelog in a pull request before it ships, or the project isn't JavaScript.
04Changesets: change files instead of commit messages
Changesets puts the release decision in the pull request itself: “Instead of parsing git commit messages, change intent is stored in dedicated Markdown files committed alongside your code.” Running changeset asks which packages changed, the semver bump type for each and a summary, and writes a Markdown file with that front matter.
changeset version“consumes all changesets”, bumps versions “and writes changelog entries for each consumed changeset”. Review the changelog at this point.changeset publish“publishes changes to npm, and creates git tags”.- The
changesets/actionGitHub Action opens a pull request with versions and changelogs updated, titled “Version Packages” by default. - It “has a focus on solving these problems for monorepos”, but the workflow also suits single packages.
A good fit when you maintain a monorepo, or contributors' commit messages aren't reliable but you can ask for a one-line summary in each pull request. The npm package changelog guide covers the registry side.
05git-cliff: just the changelog, your way
git-cliff generates “changelog files from the Git history by utilizing conventional commits as well as regex-powered custom parsers.” It's written in Rust, configured in cliff.toml, and renders with Tera templates, so you control every heading and line.
git cliff --initcreates the config;git cliff -o CHANGELOG.mdwrites the file.--unreleasedprocesses commits that don't belong to a tag,--lateststarts from the latest tag,--tagsets the tag for the newest version and--bumpbumps the version for unreleased changes.- In a monorepo, run it inside a package directory, or scope it with
--include-pathand--exclude-path. - Install it with cargo, npm (
git-cliff), pip or Homebrew, or run it in CI withorhun/git-cliff-action.
A good fit when you already tag and publish your own way and only want a better CHANGELOG.md. For a hand-rolled version with plain git commands, see how to generate a changelog from git.
06Or no tool: GitHub's generated release notes
GitHub can draft a release's notes itself: “a list of merged pull requests, a list of contributors to the release, and a link to a full changelog”, grouped by the pull request labels you list in .github/release.yml. From a terminal, gh release create v1.4.0 --generate-notes does the same. Those notes live on GitHub rather than in your repository, so keep a CHANGELOG.md too; Keep a Changelog vs GitHub Releases shows how to run both without double work, and the free LogPulse GitHub Action publishes your CHANGELOG.md section as the release on every tag. It's one workflow step, uses: kalmwerk/release-notes-action@v1 (on GitHub).
07How to choose
| If you want… | Use |
|---|---|
| Every merge to main released, no human step | semantic-release |
| A person to decide when, after reviewing the notes in a PR, in any language | release-please |
| A monorepo, or release notes that don't depend on commit messages | Changesets |
| Your existing release process, with a nicer CHANGELOG.md | git-cliff |
| A small project with well-labelled pull requests | GitHub's generated notes, edited, plus a CHANGELOG.md |
Keep a Changelog names these same tools and adds a warning worth keeping: “A generated changelog is raw material at best: a person still has to choose what is notable, group it, and write it for the reader.” Merge related lines, drop internal ones and give every breaking change a migration step; the CHANGELOG.md format guide shows the target.
Before and after
Too vague
### Features · feat: stream · feat: stream part 2 · ### Bug Fixes · fix: lexer crlf · fix: test helper
Specific and actionable
### Added · parseStream() parses large files without loading them into memory. ### Fixed · Files with Windows (CRLF) line endings now parse.
Fictional example: use your own verified names, versions and behavior.
LogPulse
Generate release notes with LogPulse
LogPulse is a hosted changelog that people and coding agents can both read. Here's exactly what it can do for the steps above, and what it can't.
Check your changelog, free
Paste a CHANGELOG.md or a GitHub releases link. A deterministic parser (no AI, nothing stored) shows the versions, breaking changes, migration steps and deprecations an agent can extract.
Draft notes from GitHub
Connect a repository: merged pull requests, commits to your default branch and published GitHub releases collect in an inbox. AI drafts a note in the tone you pick, listing breaking changes and deprecations only when the changes clearly show them. Nothing is published until you approve it. 3 AI drafts on Free; unlimited on Open source and Pro. Pro opens soon: .
Publish once, read everywhere
Approved notes go to a hosted changelog and an in-app widget, to email subscribers on Open source and Pro (Pro opens soon), and to a JSON feed and MCP server coding agents can query. CI and agents can publish with an API key.
What it doesn't do: LogPulse doesn't tag releases, bump versions, publish to npm or PyPI, or write CHANGELOG.md back to your repository; keep your release tooling for those. AI drafts can miss context, so review them like a pull request.
Before you publish
- The commit or change-file convention your tool relies on is written down in CONTRIBUTING.md
- Breaking changes are marked the way your tool expects (! or BREAKING CHANGE:, or a major change file)
- Someone reads and edits the generated notes before the release goes out
- Every breaking change has a migration step
- The changelog lives in the repository, not only on your code host
Common questions
Can semantic-release write a CHANGELOG.md?
Yes, with the @semantic-release/changelog plugin, which isn't in the default plugin list. Committing the file back to the repository needs @semantic-release/git, and semantic-release's FAQ recommends against committing during releases, so many projects keep the notes on GitHub releases instead.
Does release-please publish to npm or PyPI?
No. Its README says it “does not handle publication to package managers”. It updates the changelog and version files, tags the commit and creates the GitHub release; add a publish step to the same workflow that runs when a release is created.
Do I need Conventional Commits for Changesets?
No. Changesets reads change files that contributors add to their pull requests, not commit messages. semantic-release, release-please and git-cliff all read commit messages.
Which works for Python, Go or Rust projects?
release-please has release types for python, go, rust and more. git-cliff works on any git repository and installs from cargo, pip or npm. semantic-release can release other ecosystems through plugins, and Changesets publishes to npm.
Sources
Facts last checked against these sources on .
Read next
How to write release notes from commits (Conventional Commits)
Turn commits into release notes: the Conventional Commits format, how feat, fix and ! map to versions and sections, tools that automate it, what to edit.
Read the guide Open-source libraries and packagesKeep a Changelog vs GitHub Releases
CHANGELOG.md or GitHub Releases? See them side by side, when to use each, and how to keep both in sync with release.yml. Includes a CHANGELOG.md skeleton.
Read the guide Open-source libraries and packagesHow to keep a changelog for an npm package
Where npm users look for changes, how to keep versions, git tags and headings in sync, ship prereleases without moving latest, and deprecate old versions.
Read the guide Open-source libraries and packagesHow to generate a changelog from git commits
Generate a changelog from git: find the last tag, list commits since it with git log, credit contributors with git shortlog, use GitHub's generated notes, then edit.
Read the guideMore guides: open-source libraries and packages
- How to write release notes for open-source libraries
- Changelog vs release notes: what's the difference?
- CHANGELOG.md format, explained line by line
- Release notes templates in Markdown
- How to keep a changelog for a Python package on PyPI
Tools and resources
LogPulse
Changelogs coding agents can upgrade from.
Publish versions, breaking changes, migration steps and deprecations once. People get a widget and hosted changelog; agents get a JSON feed and MCP server. Free for open source.