Skip to main content

Release Notes Generator: Conventional Commits & CHANGELOG Guide

Writing release notes manually is time-consuming and inconsistently done under release pressure. Conventional Commits combined with automation tools like semantic-release and release-please turn your git history into structured release notes automatically — so your changelogs are always accurate, up to date, and require no extra effort on release day.

✓ Conventional Commits → release notes mapping ✓ semantic-release setup guide ✓ release-please configuration ✓ CHANGELOG.md maintenance ✓ semantic-release vs release-please comparison
Share this tool: X / Twitter LinkedIn
✓ 60,000+ developers use DevPlaybook ★★★★★ 4.8 / 5 on Gumroad ✓ MIT licensed · Instant download ✓ No login required

Related Products

on Gumroad

You Might Also Need

More Free Tools

Enjoying this tool? Get more like it.

Weekly developer tool guides, productivity playbooks & AI tricks. Free. No spam.

DevPlaybook Pro 7 days free

Unlock AI-Powered Dev Tools

  • ⚡ AI Code Review, Doc Generator & SQL Builder
  • ⚡ All premium templates & early access
  • ⚡ Member discounts on Gumroad products
Start Free Trial →

$9/mo after trial · Cancel anytime

Want the full toolkit?

Get DevPlaybook Pro

Every template, guide, boilerplate, and automation script in one bundle. 13 premium products — grab them all at once and save big.

$79
$241 separately Save $162 (67% off)
Get DevPlaybook Pro — $79 →

MIT licensed · Instant download · No subscription

See what's included → Browse all deals →

Conventional Commits → Release Notes Mapping

Conventional Commits encode intent in the commit message. Release tools read these types and map them to version bumps and changelog sections automatically.

# Commit format: type(scope): short description
#
# BREAKING CHANGE → MAJOR bump → "Breaking Changes" section
feat!: migrate authentication to OAuth 2.0
# or with footer:
feat(auth): add OAuth 2.0 support

BREAKING CHANGE: Basic auth is no longer supported. Migrate to OAuth tokens.

# feat → MINOR bump → "Features" section
feat(api): add bulk user import endpoint
feat: support dark mode in dashboard

# fix → PATCH bump → "Bug Fixes" section
fix(auth): prevent session timeout on active use
fix: correct timezone handling in date picker

# perf → PATCH bump → "Performance Improvements" section
perf(db): add index on users.email column

# These types produce PATCH but often appear in notes:
refactor: extract validation logic to separate module
docs: add API authentication examples

# These types are typically excluded from release notes:
test: add edge case coverage for date parsing
chore: upgrade dev dependencies
ci: cache npm dependencies in GitHub Actions

semantic-release GitHub Actions Setup

semantic-release is fully automated — it runs on every merge to main, determines if a release is needed, bumps the version, updates CHANGELOG.md, creates a GitHub Release, and optionally publishes to npm. Zero manual steps after setup.

# .github/workflows/release.yml
name: Release
on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      issues: write
      pull-requests: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0    # full history required for semantic-release
          persist-credentials: false
      - uses: actions/setup-node@v4
        with: { node-version: '20' }
      - run: npm ci
      - run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}   # omit if not publishing to npm

# release.config.js
module.exports = {
  branches: ['main'],
  plugins: [
    '@semantic-release/commit-analyzer',
    '@semantic-release/release-notes-generator',
    ['@semantic-release/changelog', { changelogFile: 'CHANGELOG.md' }],
    '@semantic-release/npm',
    ['@semantic-release/git', {
      assets: ['CHANGELOG.md', 'package.json'],
      message: 'chore(release): ${nextRelease.version} [skip ci]'
    }],
    '@semantic-release/github',
  ],
};

release-please: PR-Based Release Workflow

release-please creates a Release PR that accumulates all pending changes. You decide when to release by merging the PR — giving you control over timing while keeping the preparation work automated.

# .github/workflows/release-please.yml
name: Release Please
on:
  push:
    branches: [main]

jobs:
  release-please:
    runs-on: ubuntu-latest
    steps:
      - uses: googleapis/release-please-action@v4
        id: release
        with:
          release-type: node
          token: ${{ secrets.GITHUB_TOKEN }}

      # Steps below only run when the Release PR is merged (a release happens)
      - uses: actions/checkout@v4
        if: ${{ steps.release.outputs.release_created }}
      - uses: actions/setup-node@v4
        if: ${{ steps.release.outputs.release_created }}
        with:
          node-version: '20'
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci && npm publish
        if: ${{ steps.release.outputs.release_created }}
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

semantic-release vs release-please Comparison

Dimension semantic-release release-please
Release trigger Fully automatic on merge to main Manual: merge the Release PR
Release PR No — releases immediately Yes — accumulates in a PR
Monorepo support Via plugins (multi-semantic-release) Native (release-please-config.json)
Plugin ecosystem Rich (npm, GitHub, GitLab, Slack...) Focused (GitHub Releases)
Setup complexity Medium (release.config.js) Low (one action, minimal config)
Best for npm libraries, continuous delivery Apps, monorepos, controlled cadence

Frequently Asked Questions

What makes good release notes?▼

Good release notes answer three questions a user cares about: What is new (new features)? What is fixed (bugs resolved)? Does anything break (breaking changes)? Structure matters: group changes by type (Features, Bug Fixes, Breaking Changes), include a short summary at the top, link to relevant issues or PRs for context, and provide a migration path for breaking changes. Avoid developer jargon — write for the person upgrading, not the person who wrote the code.

What is Conventional Commits and why does it enable automation?▼

Conventional Commits is a specification for structuring commit messages: type(scope): description. The type encodes intent — feat for new features, fix for bug fixes, docs for documentation. Release tools parse these types to determine version bumps and categorize changes automatically. Without a consistent commit format, every release requires manual curation. With Conventional Commits, releasing becomes a single command that reads git log, determines the version, and generates formatted notes.

How do I set up semantic-release in a GitHub Actions workflow?▼

Install semantic-release: npm install --save-dev semantic-release @semantic-release/git @semantic-release/changelog. Create a release.config.js or add a 'release' key in package.json. In your GitHub Actions workflow, add a release job that runs on main with: npx semantic-release. semantic-release needs a GITHUB_TOKEN with write access to create releases. It automatically reads commits since the last tag, determines the version bump, publishes to npm (if configured), creates a GitHub Release, and updates CHANGELOG.md.

What is the difference between semantic-release and release-please?▼

Both automate releases from Conventional Commits, but with different philosophies. semantic-release runs on every merge to main and releases immediately if there are releasable commits. release-please creates a Release PR that accumulates all pending changes — you control when the release actually happens by merging the PR. Use semantic-release for fully automated, continuous release pipelines (npm libraries). Use release-please when you want a human to approve the release timing (apps, teams with release windows, Google-style projects).

How do I maintain a CHANGELOG.md manually?▼

Follow the Keep a Changelog format: each release gets a section with version and date header. Organize entries under Added, Changed, Deprecated, Removed, Fixed, Security subsections. Keep an [Unreleased] section at the top that accumulates changes since the last release. When you cut a release, rename [Unreleased] to the version and date, and create a new empty [Unreleased] section. Link version headers to git comparison URLs (e.g., github.com/owner/repo/compare/v1.0.0...v1.1.0) for diff visibility.

Can I use these tools in a monorepo with multiple packages?▼

Yes. release-please has first-class monorepo support — configure it to release each package independently with separate changelogs and version numbers using release-type per directory in release-please-config.json. semantic-release supports monorepos via the @semantic-release/exec plugin or multi-semantic-release. Nx and Turborepo both have release tooling built in. For simple monorepos, Changesets (by the Remix/Preconstruct team) is purpose-built for independently versioning multiple packages with human-authored change descriptions.