# changelogithub and the exclamation mark that changes how releases get documented

> changelogithub turns Conventional Commits into GitHub release notes, triggered by a v* tag push, with a design choice the author made after a rival tool hid breaking changes. This is a look at how it is wired, what it costs to adopt, and where the documentation stops.

**antfu-collective/changelogithub** — Generate changelog for GitHub

- Repository: https://github.com/antfu-collective/changelogithub
- Stars: 929 · Forks: 58
- Language: TypeScript
- License: MIT
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/antfu-collective-changelogithub

## A breaking change written as chore!: drop node v10

changelogithub is a small TypeScript tool that generates a changelog for GitHub releases from Conventional Commits, and it does so with changelogen doing the parsing work underneath. The specific behaviour that defines it is a single character. A commit subject such as `chore!: drop node v10` is treated as a breaking change, which the project lists as a supported feature rather than an accident.

The reason is given plainly in the README. The author used conventional-github-releaser for nearly every project until finding that it does not support exclamation marks for breaking changes, and the linked issue shows the consequence: those breaking changes end up hidden in the changelog, and the maintainers are not aware it happened. That is the gap the project sets out to close.

The rest of the feature list is short and concrete. Scope names are grouped in the output, so commits tagged with the same scope cluster together instead of arriving as an undifferentiated list. The tool either creates the release note or updates an existing one, which matters when a release has already been published as a draft. Contributors are listed in the note.

The audience is narrow and specific: maintainers of GitHub repositories that tag releases with a v prefix and whose contributors already write structured commit subjects. If your team still writes free-form messages like fixed the thing, there is nothing here to help you, because the whole pipeline depends on the commit text being machine readable.

## The only trigger is a tag that starts with v

Everything about changelogithub runs inside GitHub Actions, and the workflow file supplied in the README is the whole setup. The job asks for write permission on contents, because the tool has to put text on a release, and it checks out the repository with a full fetch depth so that the history behind the tag is available.

```yaml
name: Release

permissions:
  contents: write

on:
  push:
    tags:
      - 'v*'
```

That trigger block is the contract. The workflow fires when a tag beginning with v is pushed, and the README states the tool will be triggered whenever a tag starting with v is pushed to GitHub.

```yaml
jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
        with:
          fetch-depth: 0
```

The checkout step matters more than it looks. A shallow clone would leave the commit range for the tag empty, and there would be nothing to summarise.

```yaml
      - name: Set node
        uses: actions/setup-node@v6
        with:
          registry-url: https://registry.npmjs.org/
          node-version: lts/*

      - run: npx changelogithub # or changelogithub@0.12 to ensure a stable result
        env:
          GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
```

Note the comment on the run line. The author offers pinning to a fixed version, `changelogithub@0.12`, as a way to ensure a stable result, which is a reasonable precaution in a release job where a surprise upstream release should not change the notes your users read.

## Where configuration lives, and what it can hold

Configuration is optional and, when used, lives in one of a fixed set of places. You can put a file in the project root named `changelogithub.config.json`, `changelogithub.config.ts`, `changelogithub.config.js`, `changelogithub.config.mjs` or `changelogithub.config.cjs`, or a `.changelogithubrc` file, or you can use the `changelogithub` field in `package.json`. The loader dependency listed in the project manifest is c12, which is the configuration loader that handles this family of file names and formats.

Beyond the file names, the README does not enumerate the individual options. It does not list a setting for the release title format, for the repository field, for the previous tag used as a boundary, or for whether contributors should be listed. The README also does not document whether any of those options exist at all. That is a real constraint on evaluation: you can tell from the documentation that a configuration file is supported, but you cannot tell from the documentation what to put inside one.

The repository layout gives a hint about the project's own shape. The top level holds `.github/`, `src/`, `test/`, `package.json`, `pnpm-workspace.yaml` and a `pnpm-lock.yaml`, alongside build and lint configuration in `tsconfig.json`, `tsdown.config.ts` and `eslint.config.js`. The presence of `pnpm-workspace.yaml` indicates the tool itself is developed in a workspace, but the README says nothing about how changelogithub handles a repository that publishes several packages, so there is no documented path for per-package notes.

## Checking the note before it reaches the release

Running the tool locally without publishing anything is a single flag:

```bash
npx changelogithub --dry
```

The `--dry` flag is the only local invocation the README documents, and it is enough to confirm the shape of the output before the workflow publishes it. Because the release note is written to a GitHub release rather than committed to a file, that dry run is the only comfortable place to catch a formatting problem, since a published release note has to be edited by hand afterwards.

The package manifest confirms this is a command line program rather than a library you import. The bin entry maps the command name to the built file:

```json
  "bin": {
    "changelogithub": "./dist/cli.mjs"
  },
```

The published package also exposes two module entry points, the package root and an explicit cli path, and the files array ships only the dist directory. The scripts section shows the same split between building and running: `pnpm run build && node dist/cli.mjs` is the start script, the build step is tsdown, and the test script is vitest.

One more detail from the dependency list matters for behaviour you can observe. The project depends on convert-gitmoji, so commit messages that use gitmoji shorthand are converted on the way into the note, and ansis is in the dependency list for terminal colour output.

## The Node floor that will stop a stale runner

The package manifest sets a hard runtime requirement that is stricter than the workflow example implies. The engines field asks for Node `^22.19.0 || ^24.11.0 || >=26.0.0`, and the package is declared as ESM only through the `"type": "module"` field. The example workflow uses `lts/*`, which will resolve to a Node release outside that range on some future line, so a repository that copies the workflow verbatim is relying on setup-node picking a version the manifest still accepts.

The dependency list also mixes pinning styles, and the difference is visible rather than something to guess at. Most runtime dependencies use caret ranges, for example `c12` at `^3.3.4` and `ofetch` at `^1.5.1`. The parsing engine is different: `changelogen` is pinned to the exact version `0.5.7`. The GitHub API client ofetch, the argument parser cac, the tinyexec and tinyglobby helpers, the terminal colour library ansis and the verkit helper round out the runtime set.

Because changelogen is pinned exactly, a release of changelogithub that bumps the parser will move the output format in a way you can trace to a single dependency change rather than to a change in the tool itself. For a project whose release notes are read by users, that is worth knowing when a note looks different from the previous one.

## What the README leaves open

Several questions a maintainer will ask are simply not answered. The README does not document rollback, so if a note is generated wrongly there is no described path to restore the previous release note through the tool, and editing by hand in the GitHub interface is the only option given. The README does not document how an existing release note is reconciled when the tool is asked to update it, so whether a second run replaces the text or appends to it is left to inspection.

The README does not list the configuration keys. It also does not state which token permissions are needed beyond the `contents: write` permission in the example workflow, nor what happens when the token lacks write access, so the failure mode in a misconfigured repository is unspecified. The README does not describe the format of the generated note in prose; it links to a changelog example on the unocss repository instead, which makes the output format something you learn by looking at a real release rather than by reading a specification.

This is the honest shape of the project. It is a focused tool with a clear reason to exist, a short README, and several behaviours that a reader can only discover by running it. That is a normal trade for a utility written by one maintainer, and it is also the reason to try it on a test release first.

## What sets changelogithub apart from conventional-github-releaser

The alternative named in the README is conventional-github-releaser, the tool the author used before. The difference given is specific and testable: conventional-github-releaser does not support exclamation marks for breaking changes, so a commit such as `chore!: drop node v10` does not get the visibility it should. The README links that claim to an issue on the conventional-changelog tracker, so the gap is documented rather than merely asserted.

The rest of the difference follows from what changelogithub adds on top. Grouping by scope produces a note organised by the parts of the codebase that changed, which is a different structure from a flat list of subjects. Listing contributors attaches the set of people who contributed to the release. Updating an existing note lets the same job handle a release that was published before the run finished.

There is also a difference in where the work happens. changelogithub talks to the GitHub API through ofetch, using the token supplied in the environment, and the parsing is handled by changelogen rather than by the conventional-changelog family of packages. The practical consequence for an adopter is the trigger: this one runs from a workflow on a v tag, and its output is attached to a GitHub release.

## The licence and the release cadence behind the version numbers

The licence field on the repository says MIT, and the README credits the licence to Anthony Fu with a 2022 copyright line. MIT is a permissive licence, so a project that vendors this tool internally is not obliged to publish changes, though the tool itself is distributed as an npm package under the same terms. Nothing here needs legal review for ordinary internal use; the details of your own situation are outside what the repository states.

The version numbers move on a different scale from the release history of most projects. The manifest version is 15.0.5, and the published releases listed for the repository are v15.0.5 on 2026-08-27, v15.0.4 on 2026-07-29 and v15.0.3 on 2026-07-22. The last push to the repository was on 2026-08-27. The repository is not archived.

That means the tool is still receiving work, and the upgrade path for an adopter is the npm version rather than a breaking change in the GitHub Actions workflow. The command line surface is small enough that the upgrade risk sits mostly in the changelogen pin and in the output format, which is exactly why the `--dry` run and the pinned `changelogithub@0.12` comment in the README are worth following rather than ignoring.

## Conclusion

changelogithub fits a repository that already tags releases as v*, writes Conventional Commits, and wants the release note written on the GitHub release itself rather than in a file in the tree. It is a poor fit for a project that has not standardised its commit messages, for a monorepo that needs per-package notes, or for a team that needs a rollback path, because the README does not document one. Before adopting it, check that your CI token scope is enough for the release it has to write, pin the version you test with instead of relying on the floating tag, and confirm on a throwaway release that the note it produces matches the format your readers expect.

## FAQ

### How do I generate a changelog for a GitHub release with changelogithub?

Add a GitHub Actions workflow that triggers on tags starting with v and runs `npx changelogithub` with `GITHUB_TOKEN` set in the environment. The README provides that workflow as the usage example, with `contents: write` in the job permissions.

### Does changelogithub treat an exclamation mark as a breaking change?

Yes. The project lists support for the exclamation mark as a breaking change, giving the example `chore!: drop node v10`. The README says the author moved away from conventional-github-releaser because that tool did not support exclamation marks and hid those breaking changes.

### Which Node.js versions can run changelogithub?

The package manifest requires `^22.19.0 || ^24.11.0 || >=26.0.0` and declares the package as an ES module. The example workflow uses `node-version: lts/*`.

### Can I preview the release note before it is published?

Yes, the README gives a local preview command, `npx changelogithub --dry`. The command runs the same tool without writing the release note.

### Where does changelogithub read its configuration from?

The README names `changelogithub.config.{json,ts,js,mjs,cjs}` in the project root, a `.changelogithubrc` file, or the `changelogithub` field in `package.json`. It does not list the individual configuration keys.

## Sources

- [antfu-collective/changelogithub on GitHub](https://github.com/antfu-collective/changelogithub)
- [Issues](https://github.com/antfu-collective/changelogithub/issues)
- [License: MIT](https://github.com/antfu-collective/changelogithub/blob/main/LICENSE)
- [README](https://github.com/antfu-collective/changelogithub/blob/main/README.md)
- [Releases](https://github.com/antfu-collective/changelogithub/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/antfu-collective-changelogithub
