github-actionschangelogautomationrelease-notesci-cddevopsrelease-managementdeveloper-tools

How to Automate Your Changelog with GitHub Actions (Step-by-Step)

Cristobal MitchellFounder of ReleaseRay··10 min read
Share:

Every repository has a CHANGELOG.md. Most of them are lies. They were last updated three months ago, they skip half the releases, and the entries that do exist were clearly written by someone who was already mentally on to the next sprint. If you've ever committed a changelog entry that said "miscellaneous improvements" because you couldn't remember what changed since the last tag, you've felt this problem in your bones.

The fix isn't discipline. The fix is automation. If you're already using GitHub Actions to build, test, and deploy your code, the changelog should be part of that pipeline. The question is which tool does it best for your team.

I'm going to walk through four real approaches, each with working configuration you can copy. I'll be honest about where each one shines and where it falls short. If you've read our guide to automating branch promotions with GitHub Actions, this is the natural next step: once your code flows automatically from develop to staging to production, the changelog should flow with it.


The Problem: Manual Changelogs Don't Scale

You know the routine. Release day arrives. Someone opens CHANGELOG.md, scrolls past the last entry from two sprints ago, and starts piecing together what shipped. They open GitHub, compare tags, skim PR titles, try to figure out which ones matter to users, and start typing.

It takes an hour if you're fast, two if you're thorough, and the result is still inconsistent. The engineer who wrote last month's changelog bolded the breaking changes. The one who wrote this month's forgot they exist. Your PM reads the changelog and has no idea what any of it means because it's written in implementation detail, not user impact.

This isn't a people problem. It's an infrastructure problem. Every manual process that depends on a human remembering to do it, and doing it consistently, will degrade over time. Changelogs degrade fast because nobody's performance review mentions them.

So let's automate them. Here are four ways to do it, starting with the simplest.


Option 1: Release Drafter

Release Drafter is the most popular changelog automation tool on GitHub, and for good reason. It's free, it's maintained, and it works with a pattern most teams already follow: labeling PRs.

The idea is straightforward. You define categories in a YAML config file. When a PR merges with a label like feature or bugfix, Release Drafter slots it into the right section of a draft GitHub Release. When you're ready to ship, the release notes are already written.

Here's the workflow:

name: Release Drafter
on:
  push:
    branches: [main]
  pull_request:
    types: [opened, reopened, synchronize]

permissions:
  contents: read
  pull-requests: write

jobs:
  update_release_draft:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - uses: release-drafter/release-drafter@v6
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

And the configuration file (.github/release-drafter.yml):

name-template: "v$RESOLVED_VERSION"
tag-template: "v$RESOLVED_VERSION"
categories:
  - title: "New Features"
    labels:
      - "feature"
      - "enhancement"
  - title: "Bug Fixes"
    labels:
      - "bug"
      - "bugfix"
  - title: "Breaking Changes"
    labels:
      - "breaking"
  - title: "Maintenance"
    labels:
      - "chore"
      - "dependencies"
change-template: "- $TITLE @$AUTHOR (#$NUMBER)"
version-resolver:
  major:
    labels: ["breaking"]
  minor:
    labels: ["feature", "enhancement"]
  patch:
    labels: ["bug", "bugfix", "chore"]
  default: patch
template: |
  ## Changes

  $CHANGES

  ## Contributors
  $CONTRIBUTORS

Where Release Drafter excels: It's zero-cost, it produces clean GitHub Releases, and the version resolver handles semver bumps based on labels. For open-source projects where contributors already label their PRs, this is the path of least resistance.

Where it falls short: It requires label discipline. If your team doesn't consistently label PRs (and most teams don't, if we're being honest), the changelog has gaps. Unlabeled PRs either get dumped into an "Other" category or disappear entirely. The output is also a single format. Your engineers and your customers see the same thing. For a library with a technical audience, that's fine. For a SaaS product with end users, it's not enough.

Release Drafter also only generates GitHub Releases. If you need CHANGELOG.md updates, Slack notifications, or customer-facing release notes, you're writing additional automation on top.


Get release management tips in your inbox

Practical guides on release notes, changelogs, and shipping better software. No spam, unsubscribe anytime.

Option 2: Changesets

Changesets takes a fundamentally different approach. Instead of inferring what changed from PR metadata, it asks the developer to declare it explicitly at the time of the PR. When you're ready to release, a CLI command consumes all the changeset files, bumps versions, and generates a changelog.

The workflow starts with a developer adding a changeset to their PR:

npx changeset

This creates a markdown file in .changeset/ describing the change and its semver impact:

---
"@myorg/api": minor
"@myorg/shared": patch
---

Add rate limiting to the draft generation endpoint.
Allows configuration of per-user limits via environment variables.

The GitHub Action that manages releases looks like this:

name: Release
on:
  push:
    branches: [main]

permissions:
  contents: write
  pull-requests: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: "20"
      - run: npm ci
      - name: Create Release Pull Request or Publish
        uses: changesets/action@v1
        with:
          publish: npx changeset publish
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Where Changesets excels: Monorepos. If you're managing multiple packages that version independently (think a design system with @myorg/button, @myorg/input, @myorg/theme), Changesets handles cross-package version bumps, per-package changelogs, and coordinated publishing better than anything else. The developer writes the changelog entry while the context is fresh, which usually produces higher-quality descriptions than anything generated from PR titles after the fact.

Where it falls short: Adoption. Every PR needs a changeset file, which means every developer on the team needs to understand the workflow. If someone forgets (and they will), you need a CI check that blocks the PR until a changeset is added, which introduces friction. For teams that aren't shipping npm packages, the overhead-to-value ratio is hard to justify. And the output, like Release Drafter, is a single format, one changelog for all audiences.

Changesets also has a meaningful learning curve. The mental model (a .changeset/ directory of markdown files that get consumed on release) is elegant once you internalize it, but it's one more thing to teach new team members.


Option 3: Conventional Commits + Auto-Changelog

If your team already follows (or wants to follow) the Conventional Commits specification, you can generate changelogs directly from your commit history. The idea is simple: if every commit message follows type(scope): description, a tool can parse those messages and produce a structured changelog automatically.

If you're not yet enforcing conventional commits, our guide to enforcing semantic versioning with AI assistant rules shows how to set that up in your editor with free rule files for Cursor, Copilot, and Claude Code.

Here's a GitHub Actions workflow using conventional-changelog to update CHANGELOG.md on every release:

name: Generate Changelog
on:
  push:
    tags:
      - "v*"

permissions:
  contents: write

jobs:
  changelog:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - run: npm install -g conventional-changelog-cli

      - name: Generate changelog
        run: conventional-changelog -p angular -i CHANGELOG.md -s -r 0

      - name: Commit updated changelog
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add CHANGELOG.md
          git commit -m "docs: update CHANGELOG.md for ${{ github.ref_name }}"
          git push

For a more sophisticated setup, semantic-release combines version bumping, changelog generation, and GitHub Release creation into a single step:

name: Release
on:
  push:
    branches: [main]

permissions:
  contents: write
  issues: write
  pull-requests: write

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - uses: actions/setup-node@v4
        with:
          node-version: "20"

      - run: npm ci

      - name: Semantic Release
        run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

With a .releaserc.json:

{
  "branches": ["main"],
  "plugins": [
    "@semantic-release/commit-analyzer",
    "@semantic-release/release-notes-generator",
    ["@semantic-release/changelog", { "changelogFile": "CHANGELOG.md" }],
    "@semantic-release/github",
    [
      "@semantic-release/git",
      {
        "assets": ["CHANGELOG.md", "package.json"],
        "message": "chore(release): ${nextRelease.version} [skip ci]"
      }
    ]
  ]
}

Where Conventional Commits tooling excels: It's entirely derived from your Git history. No separate files, no labels, no manual steps. If your team writes good commit messages (a big if), the changelog writes itself. The semantic-release ecosystem is mature, well-documented, and handles everything from version bumps to npm publishing to GitHub Releases.

Where it falls short: Commit messages are written for developers, not for users. fix(auth): resolve race condition in token refresh is great information for the engineer reviewing the changelog. It means nothing to a customer who wants to know if their login issues are fixed. The gap between what commit messages describe (implementation) and what changelogs should describe (impact) is the gap this approach cannot close.

There's also the enforcement problem. Conventional commits only work if every commit follows the convention. One fixed stuff or WIP commit breaks the chain. You need commitlint in your CI pipeline, which means more configuration, more things to maintain, and more onboarding friction for new contributors.


Option 4: ReleaseRay

I built ReleaseRay because I ran into the limitations of the three approaches above. Release Drafter required label discipline my team didn't have. Changesets added friction to every PR for a product that doesn't ship npm packages. Conventional commits produced technically accurate changelogs that my PM couldn't use in customer calls.

ReleaseRay takes a different approach. It installs as a GitHub App, watches your repository for merged PRs and closed issues, and uses LLM-powered analysis to generate three distinct versions of your release notes: one for engineers (technical, PR-referenced), one for internal teams and CSMs (impact-focused, talking points), and one for customers (plain language, benefit-driven).

The setup is a GitHub App installation. There's no workflow file to add, no YAML to configure, and no commit convention to enforce. ReleaseRay reads your PR titles, descriptions, linked issues, and commit messages, classifies the changes, and generates structured release notes.

It works with whatever conventions you already follow. If you use Conventional Commits, great, ReleaseRay uses those signals for better classification. If your PRs are labeled, it uses those too. If neither, it still works, because the LLM can infer change categories from PR titles and descriptions.

Publishing is multi-channel. From a single generated draft, you can publish to GitHub Releases, update CHANGELOG.md via automated PR, send Slack notifications, post to Intercom Help Center, email subscribers, or publish to a hosted changelog page. One click, all channels.

Where ReleaseRay excels: Audience awareness. The same set of changes produces three different outputs without any extra work. The engineer gets PR references and upgrade instructions. The PM gets customer impact summaries. The customer gets plain language and benefit framing. Each version is a first draft that you can edit, not a final product you have to accept.

It also handles the publishing distribution that the other tools don't touch. Release Drafter generates a GitHub Release. ReleaseRay generates a GitHub Release, a CHANGELOG.md update, Slack messages, email notifications, and an Intercom article from the same source material.

Where it falls short: It's a paid product (starting at $5/month). If you're an open-source project with a tight budget and a technical audience, Release Drafter or Conventional Commits may genuinely be the better fit. ReleaseRay also requires a GitHub App installation, which some organizations restrict.


Comparison

Here's an honest side-by-side of all four approaches:

Release DrafterChangesetsConv. CommitsReleaseRay
Setup time10 min30 min20 min10 min
MaintenanceLow (labels)Medium (changeset files)Medium (commitlint)Low (managed)
Output qualityPR titlesDeveloper-writtenCommit messagesLLM-generated drafts
Multi-audienceNoNoNoYes (3 personas)
CHANGELOG.mdNo (GitHub Release only)YesYesYes (via automated PR)
Multi-channelNoNo (npm focus)Via pluginsYes (6 channels)
Multi-repoPer-repo configMonorepo focusPer-repo configDashboard across repos
Convention requiredPR labelsChangeset filesCommit formatNone
CostFreeFreeFreeFrom $5/mo
Best forOSS, labeled PRsMonorepo packagesStrict commit cultureTeams wanting audience-aware notes

Which Approach Fits Your Team

Solo developer or small open-source project: Start with Release Drafter. It's free, it's simple, and a solo maintainer can keep label discipline because there's only one person to discipline. Add Conventional Commits if you want CHANGELOG.md updates from semantic-release.

Monorepo with multiple publishable packages: Changesets is the right tool. The per-package versioning and coordinated releases solve a genuine problem that the other tools don't address. The friction of writing changeset files is worth it when you need independent version management across a dozen packages.

Team with strong commit discipline (or willing to build it): Conventional Commits with semantic-release gives you a fully automated pipeline from commit to published release. If your team already writes structured commit messages, this is the lowest-effort path to changelog automation. If your team doesn't, read our semantic versioning enforcement guide first.

Product team shipping to non-technical users: This is where the single-format tools fall short. If your changelog needs to serve engineers, PMs, and customers, you need audience-aware generation. You could write three versions manually (and spend triple the time), or let ReleaseRay generate them from the same source material. The 10-minute setup saves 2+ hours per release cycle. Do the math.

Growing team that wants all of the above: ReleaseRay complements the other tools rather than replacing them. You can keep Conventional Commits for commit hygiene, keep semantic-release for version bumps, and add ReleaseRay for the audience-aware drafts and multi-channel publishing that the commit-based tools don't handle. They're not mutually exclusive.


Getting Started

If you want to try the simplest path first, copy the Release Drafter workflow above and add it to your repository. You'll have automated GitHub Releases in ten minutes.

If you want audience-aware release notes without the configuration overhead, set up ReleaseRay and connect your repository. The first 14 days are free, no credit card required, and you'll see your first generated draft the next time a PR merges.

Whatever you choose, stop writing changelogs by hand. Your team's time is worth more than that.

Enjoyed this post?

Practical guides on release notes, changelogs, and shipping better software. No spam, unsubscribe anytime.

C

Cristobal Mitchell

Founder of ReleaseRay

Building ReleaseRay — automated release notes from GitHub PRs for developers, PMs, and customers.

Ready to automate your release notes?

We value your privacy

We use cookies to enhance your experience. Essential cookies are required for the site to function. You can choose to accept all cookies or manage your preferences.