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.
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:
- Deciding what version bump is warranted (major/minor/patch)
- Updating
package.json(or multiplepackage.jsonfiles in a monorepo) - Writing a changelog entry
- Creating a git tag
- Publishing to npm
- 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: 0is required — Semantic Release needs full git history.
Monorepo Support
Semantic Release doesn’t natively support monorepos. The recommended approach:
@semantic-release/exec— run per-package release scripts- multi-semantic-release — community plugin for running Semantic Release on each package
- 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
| Feature | Changesets | Semantic Release | Release Please |
|---|---|---|---|
| Monorepo native | Yes | Plugins only | Yes |
| Commit format required | No | Yes (Conv. Commits) | Yes (Conv. Commits) |
| Developer input | Manual changeset files | None | None |
| Release gate | ”Version Packages” PR | Immediate on push | Release PR |
| Language support | JS/TS (npm) | Any (via plugins) | 20+ languages |
| GitHub Actions | changesets/action | Manual workflow | release-please-action |
| CI complexity | Medium | High | Low |
| Changelog quality | High (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
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.
Affiliate disclosure: Some links below are affiliate links — we may earn a small commission at no extra cost to you. Learn more.
Recommended Tools & Resources
DigitalOcean
$200 credit for new users. Simple, affordable cloud hosting for developers.
GitHub Student Pack
Free access to 100+ developer tools. Perfect for students and new devs.
Vercel
Deploy frontend apps instantly. Free tier is generous for side projects.
DevPlaybook Products
Boilerplates, scripts & AI toolkits to 10x your dev workflow.