Skip to main content
← All Articles · · 11 min read

Changesets vs Semantic Release vs Release Please: Monorepo Release Automation 2026

Automated versioning and changelog generation for monorepos in 2026. Deep comparison of Changesets, Semantic Release, and Release Please — covering CI/CD integration, GitHub Actions workflows, and which tool fits your team.

monoreporelease-automationchangesetssemantic-releaserelease-pleasechangelogversioninggithub-actionsci-cd

Versioning and changelog management are among the highest-friction parts of shipping software. Done manually, they’re error-prone and often skipped. Done right with automation, they become invisible — your CI pipeline bumps versions, writes changelogs, and creates GitHub releases without human intervention.

In 2026, three tools dominate monorepo release automation: Changesets, Semantic Release, and Release Please. Each solves the same core problem with different tradeoffs.


The Problem They Solve

Without automation, shipping a new version involves:

  1. Deciding what version bump is warranted (major/minor/patch)
  2. Updating package.json (or multiple package.json files in a monorepo)
  3. Writing a changelog entry
  4. Creating a git tag
  5. Publishing to npm
  6. Creating a GitHub release

Miss any step, inconsistently apply semver, or forget to update a changelog — and you’ve created support tickets and broken dependent projects.

Release automation tools handle all of this, usually triggered by commit messages or explicit change files.


Changesets

Changesets is built by the Atlassian team and designed specifically for monorepos. The core workflow: developers add “changesets” (small markdown files) alongside their PR, and the CI pipeline consumes them to determine version bumps and generate changelogs.

How It Works

your-monorepo/
├── .changeset/
│   ├── config.json
│   └── blue-shoes-dance.md   ← changeset file added by developer
├── packages/
│   ├── core/
│   └── utils/

Adding a changeset (run by the developer before merging a PR):

npx changeset

This prompts you to select affected packages and bump type:

Which packages would you like to include?
◉ @myorg/core
◯ @myorg/utils

Which type of change is this for @myorg/core?
  patch
  minor
❯ major

Creates .changeset/blue-shoes-dance.md:

---
"@myorg/core": major
---

Rewrote the authentication module to use JWT instead of sessions.
Breaking: `authenticate()` now returns a Promise instead of a callback.

Releasing (typically in CI):

npx changeset version   # bumps package.json versions, updates CHANGELOG.md
npx changeset publish   # publishes to npm, creates git tags

GitHub Actions Workflow

name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci
      - uses: changesets/action@v1
        with:
          publish: npm run release
          version: npm run version
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

The changesets/action creates a “Version Packages” PR that accumulates all pending changesets. When merged, it publishes automatically.

.changeset/config.json

{
  "$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [],
  "access": "restricted",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": []
}

Pros:

  • Purpose-built for monorepos with multiple packages
  • Developer-friendly: change intent captured at PR time, not from commit messages
  • Produces clean, human-readable changelogs
  • Handles complex dependency graphs between packages

Cons:

  • Requires developer discipline to add changesets (can be enforced via CI check)
  • More manual than commit-message-based tools
  • Learning curve for new contributors

Semantic Release

Semantic Release is fully automated — no manual files to create. It reads your commit messages (using Conventional Commits format) and derives the next version bump automatically.

How It Works

Commit messages drive everything:

feat: add OAuth2 support         → minor bump (0.x.0)
fix: handle null user edge case  → patch bump (0.0.x)
feat!: redesign auth API         → major bump (x.0.0)
  BREAKING CHANGE: ...

Install:

npm install --save-dev semantic-release \
  @semantic-release/commit-analyzer \
  @semantic-release/release-notes-generator \
  @semantic-release/changelog \
  @semantic-release/npm \
  @semantic-release/github \
  @semantic-release/git

.releaserc.json:

{
  "branches": ["main", {"name": "beta", "prerelease": true}],
  "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"
  ]
}

GitHub Actions Workflow:

name: Release

on:
  push:
    branches: [main, beta]

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
      - run: npx semantic-release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Important: fetch-depth: 0 is required — Semantic Release needs full git history.

Monorepo Support

Semantic Release doesn’t natively support monorepos. The recommended approach:

  1. @semantic-release/exec — run per-package release scripts
  2. multi-semantic-release — community plugin for running Semantic Release on each package
  3. Separate pipelines — each package in its own workflow
# For each package in a monorepo
- run: npx semantic-release
  working-directory: packages/core
  env:
    GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
    NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

Pros:

  • Fully automated — zero developer friction after initial setup
  • Clean changelogs generated from structured commit messages
  • Wide plugin ecosystem (Slack notifications, Docker tagging, etc.)
  • Works great for single-package repositories

Cons:

  • Requires strict Conventional Commits discipline
  • Monorepo support is bolted on, not native
  • Can feel like a black box — hard to debug when versioning behaves unexpectedly

Release Please

Release Please is Google’s answer to release automation. Like Semantic Release, it reads Conventional Commits — but instead of releasing immediately, it creates a “Release PR” that accumulates commits until merged.

How It Works

┌─────────────────┐      ┌──────────────────┐      ┌─────────────┐
│  Push commits   │ ───▶ │  Release Please  │ ───▶ │ Release PR  │
│  to main branch │      │  bot analyzes    │      │ created/    │
│  (conv. commits)│      │  commit messages │      │ updated     │
└─────────────────┘      └──────────────────┘      └──────┬──────┘
                                                           │
                                                           ▼
                                                   ┌─────────────┐
                                                   │ Human merges│
                                                   │ Release PR  │
                                                   └──────┬──────┘
                                                          │
                                                          ▼
                                                  ┌──────────────┐
                                                  │ Tag created, │
                                                  │ GitHub       │
                                                  │ Release made │
                                                  └──────────────┘

GitHub Actions Workflow:

name: Release Please

on:
  push:
    branches: [main]

permissions:
  contents: write
  pull-requests: write

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

  publish:
    needs: release-please
    if: ${{ needs.release-please.outputs.release_created }}
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: 'https://registry.npmjs.org'
      - run: npm ci
      - run: npm publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Monorepo Configuration (release-please-config.json)

{
  "packages": {
    "packages/core": {
      "release-type": "node",
      "package-name": "@myorg/core"
    },
    "packages/utils": {
      "release-type": "node",
      "package-name": "@myorg/utils"
    }
  }
}

Pros:

  • No npm required — works for any language (Node, Go, Python, Java via release-type)
  • Release PR gives humans a review gate before publishing
  • Native monorepo support via config
  • Backed by Google — used in googleapis/* repos

Cons:

  • Requires Conventional Commits (same as Semantic Release)
  • Release PR can feel like extra overhead for small teams
  • Less flexible plugin ecosystem than Semantic Release

Comparison Table

FeatureChangesetsSemantic ReleaseRelease Please
Monorepo nativeYesPlugins onlyYes
Commit format requiredNoYes (Conv. Commits)Yes (Conv. Commits)
Developer inputManual changeset filesNoneNone
Release gate”Version Packages” PRImmediate on pushRelease PR
Language supportJS/TS (npm)Any (via plugins)20+ languages
GitHub Actionschangesets/actionManual workflowrelease-please-action
CI complexityMediumHighLow
Changelog qualityHigh (human-written)Good (auto-generated)Good (auto-generated)

Which Tool Fits Your Team?

Choose Changesets if:

  • You have a JS/TS monorepo with multiple published packages
  • You want changelogs written by developers (not derived from commit messages)
  • Your team has varying commit discipline

Choose Semantic Release if:

  • You have a single package or simple repo
  • Your team enforces Conventional Commits via commitlint
  • You want zero-touch automation with no review gate

Choose Release Please if:

  • You want a review gate before each release
  • Your monorepo has non-JS packages
  • You want official Google backing and simpler config

Quick Start: Changesets in 5 Minutes

# 1. Install
npm install --save-dev @changesets/cli

# 2. Initialize
npx changeset init

# 3. Add a changeset (before merging a PR)
npx changeset

# 4. Version packages (CI or local)
npx changeset version

# 5. Publish
npx changeset publish

That’s the complete workflow. Add the GitHub Actions config above and you have a fully automated release pipeline.


Auto Changelog Generation Pattern

All three tools integrate with GitHub releases. Here’s the minimum viable setup for any tool:

Commit → CI analyzes → Version bumped → CHANGELOG.md updated → Git tag → GitHub Release created → npm published

The key insight: the changelog should be generated from the same source of truth as the version bump decision. Whether that’s changeset files (Changesets), commit messages (Semantic Release / Release Please), the output is consistent and automated.


Related: Node.js Version Manager Comparison 2026 | Git Hooks and Code Quality Automation

Free Download

50 CLI Commands That Save Hours Every Week

The exact Git shortcuts, file search tricks, Docker commands, and productivity hacks that senior developers use daily. Compiled from 5+ years of shipping production code.

  • Git mastery (10 cmds)
  • File & search wizardry
  • Docker & DevOps tricks
  • Process & network tools
  • Productivity boosters
  • macOS & Linux install guide

No spam. 1 email/week max. Unsubscribe anytime.

Found this guide useful? Check out our free developer tools.