Fix: Changesets Not Working — Version Not Bumping, Changelog Empty, or GitHub Action Failing
Part of: JavaScript & TypeScript Errors
Quick Answer
How to fix @changesets/cli issues — changeset creation, version bumping, changelog generation, monorepo support, npm publishing, and GitHub Actions automation.
The Problem
changeset version doesn’t bump the version:
npx changeset version
# No changes were detected — nothing to versionOr the changelog is empty after versioning:
CHANGELOG.md exists but has no entriesOr the GitHub Action fails to create a PR:
Error: No changesets found — or —
Error: GITHUB_TOKEN does not have permissionWhy This Happens
Changesets is a versioning and changelog management tool for JavaScript packages. It tracks intentional changes through changeset files:
- Changesets must be created before versioning —
changeset versionreads.changeset/*.mdfiles to determine what to bump. Without changeset files, there’s nothing to version. - Each changeset file describes one logical change — running
npx changesetcreates a markdown file in.changeset/that specifies which packages changed and the bump type (major/minor/patch). Forgetting to create changesets meansversionhas nothing to do. - Monorepo dependencies are tracked — in a monorepo, bumping package A may require bumping package B if B depends on A. Changesets handles this automatically but needs correct workspace configuration.
- GitHub Actions need specific permissions — the Changesets GitHub Action creates PRs and pushes tags. It needs
contents: writeandpull-requests: writepermissions.
A second class of failure shows up only in monorepos. Changesets discovers packages through your workspace manifest — workspaces in package.json for npm/Yarn, or pnpm-workspace.yaml for pnpm. Turborepo and Nx do not own the workspace layout; they simply orchestrate tasks across whatever the package manager already discovered. So a Turborepo or Nx setup with the wrong workspace globs causes Changesets to think a package does not exist, and changeset version quietly skips it. Worse, when linked or fixed entries reference a package Changesets cannot find, the CLI exits zero with no warning.
A third class of failure shows up only in CI. The Changesets GitHub Action does two distinct things on every run: it either creates a “Version Packages” PR (when changesets exist on main) or it publishes (when the PR has been merged and no unconsumed changesets remain). If the action fails to create the PR, that is almost always a permissions or branch-protection issue. If it fails to publish, the cause is almost always the npm token, the registry URL, or a missing NODE_AUTH_TOKEN. Bots like Renovate and Dependabot also interact with Changesets: they can add commits that should have a changeset attached, and the changeset-bot will warn on PRs that touch source without a .changeset/ entry.
Fix 1: Setup
npm install -D @changesets/cli
npx changeset init
# Creates .changeset/ directory with config.json// .changeset/config.json
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}Fix 2: Create and Apply Changesets
# Step 1: Create a changeset (interactive)
npx changeset
# Prompts:
# Which packages? -> Select packages that changed
# Bump type? -> major / minor / patch
# Summary? -> "Add user authentication with OAuth support"
# This creates a file like .changeset/happy-dogs-run.md:---
"my-package": minor
---
Add user authentication with OAuth support# Step 2: Version — reads changesets and bumps versions
npx changeset version
# This:
# 1. Reads all .changeset/*.md files
# 2. Bumps package.json versions accordingly
# 3. Updates CHANGELOG.md
# 4. Deletes consumed changeset files
# Step 3: Publish to npm
npx changeset publish
# Or manually:
npm publish// package.json — scripts
{
"scripts": {
"changeset": "changeset",
"version": "changeset version",
"publish": "changeset publish",
"release": "npm run build && changeset publish"
}
}Fix 3: Monorepo Configuration
// .changeset/config.json — monorepo settings
{
"changelog": ["@changesets/changelog-github", { "repo": "user/repo" }],
"commit": false,
"access": "public",
"baseBranch": "main",
// Fixed versioning — all packages bump together
"fixed": [["@myorg/core", "@myorg/react", "@myorg/vue"]],
// Linked versioning — bump together but can have different versions
"linked": [["@myorg/utils", "@myorg/shared"]],
// Ignore packages (don't version/publish)
"ignore": ["docs", "examples", "@myorg/internal-tools"],
// When a dependency bumps, bump dependents
"updateInternalDependencies": "patch"
}# Install GitHub changelog for rich changelogs with PR links
npm install -D @changesets/changelog-github<!-- Example generated CHANGELOG.md with GitHub changelog -->
# @myorg/core
## 2.1.0
### Minor Changes
- Add OAuth authentication support ([#123](https://github.com/user/repo/pull/123)) by @developer
### Patch Changes
- Updated dependencies
- @myorg/[email protected]# Monorepo changeset — select multiple packages
npx changeset
# Which packages? -> @myorg/core, @myorg/react
# What type for @myorg/core? -> minor
# What type for @myorg/react? -> patch
# Summary -> "Add OAuth support"Fix 4: GitHub Actions Automation
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
concurrency: ${{ github.workflow }}-${{ github.ref }}
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
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build
- name: Create Release PR or Publish
id: changesets
uses: changesets/action@v1
with:
# Commands to run
version: npx changeset version
publish: npx changeset publish
# PR title and body
title: 'chore: version packages'
commit: 'chore: version packages'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}How it works:
- Developer creates a PR with a changeset file
- PR is merged to
main - GitHub Action detects changesets -> creates a “Version Packages” PR
- Merging the Version PR triggers the publish step
- Packages are published to npm with proper versions and changelogs
Fix 5: Pre-Release Versions
# Enter pre-release mode
npx changeset pre enter beta
# Now all versions are suffixed: 1.2.0-beta.0, 1.2.0-beta.1, etc.
# Create changesets as normal
npx changeset
# Version with pre-release suffix
npx changeset version
# Publish as beta
npx changeset publish --tag beta
# Exit pre-release mode when ready for stable
npx changeset pre exit
npx changeset version # Now bumps to stable: 1.2.0
npx changeset publish// package.json — tag pre-releases on npm
{
"scripts": {
"publish:beta": "changeset publish --tag beta",
"publish:rc": "changeset publish --tag rc",
"publish:stable": "changeset publish"
}
}Fix 6: Snapshot Releases (For Testing)
# Snapshot — publish a unique version for testing (doesn't consume changesets)
npx changeset version --snapshot canary
# Publishes as: 0.0.0-canary-20260329T120000
npx changeset publish --tag canary --no-git-tag
# Install snapshot version for testing
npm install my-package@canary# GitHub Action — publish snapshot on every PR
name: Snapshot
on: pull_request
jobs:
snapshot:
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 && npm run build
- run: npx changeset version --snapshot pr-${{ github.event.number }}
- run: npx changeset publish --tag pr-${{ github.event.number }} --no-git-tag
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}Fix 7: Platform-Specific Setup — Monorepos, JSR, and Bots
Turborepo, Nx, and pnpm workspaces: Changesets discovers packages via the workspace manifest, not via Turborepo or Nx. Verify discovery first:
# See exactly which packages Changesets knows about
npx changeset status --verbose
# If a package is missing, check the manifest
cat pnpm-workspace.yaml # pnpm
node -e "console.log(require('./package.json').workspaces)" # npm/Yarn
# Common mistake: a package in apps/ but workspace glob only covers packages/*For Turborepo, run the release pipeline through turbo run release so build outputs are cached and dependent packages get their fresh dist/ before Changesets reads package.json. For Nx, prefer nx run-many -t build --projects=tag:publishable ahead of changeset publish. The order matters: Changesets reads the just-bumped versions on disk; if your build copies files using a stale version string, the tarball ships with the wrong number.
npm vs JSR publish: Changesets is npm-native. To publish to JSR (jsr.io, Deno’s registry), generate a deno.json per package after changeset version and run npx jsr publish instead of (or in addition to) npx changeset publish. Some teams write a small post-version script that syncs the version into deno.json and jsr.json so both registries stay in lockstep.
# Post-version sync example
npx changeset version
node scripts/sync-jsr-version.mjs # copies version from package.json into jsr.json
git add jsr.jsonPer-branch pre-release modes: put long-lived next or beta branches into pre-release mode and merge to them separately from main:
git checkout -b next
npx changeset pre enter next
# Every "changeset version" on this branch produces x.y.z-next.N
# When you cut a release, run "pre exit" then merge back to mainThis pattern works well with Renovate auto-updates pointed at next — the bot opens PRs against the pre-release branch, the Changesets action publishes pre-releases on every merge, and you only promote to stable when ready.
Renovate and Dependabot interaction: dependency bots do not create changesets by default. Install the changeset-bot GitHub app so PRs without a changeset get a comment, and configure Renovate to add a changeset via its postUpgradeTasks:
// renovate.json
{
"postUpgradeTasks": {
"commands": ["npx -y @changesets/cli add --empty"],
"fileFilters": [".changeset/*.md"],
"executionMode": "branch"
}
}For Dependabot, add a small workflow that runs on dependabot[bot] PRs and appends an empty changeset before tests run. Without this, your “Version Packages” PR drifts behind your main branch every time a bot merges.
Still Not Working?
“No changesets found” — no .changeset/*.md files exist (other than README.md). Run npx changeset to create one before running npx changeset version. Each changeset file must have YAML frontmatter specifying packages and bump types.
Version bumps but changelog is empty — the changeset file has no description text after the YAML frontmatter. The text below --- becomes the changelog entry. An empty body produces an empty changelog.
GitHub Action can’t create PR — the workflow needs permissions: { contents: write, pull-requests: write }. Also ensure GITHUB_TOKEN has the right scopes. For organization repos, check branch protection rules allow the GitHub Actions bot to push.
Monorepo packages not detected — Changesets reads workspaces from package.json or pnpm-workspace.yaml. Verify your workspace configuration includes all packages. Run npx changeset status to see which packages Changesets knows about.
Action creates the PR but publish step never runs — the publish step only runs when there are no unconsumed changesets on main. If the “Version Packages” PR was squashed or rebased in a way that lost the auto-merge of consumed changesets, the next push to main may still see changeset files and re-enter “create PR” mode. Inspect .changeset/ on main after merge and delete stale files manually if needed.
changeset publish fails with 401/403 from npm — your NPM_TOKEN is missing the publish scope or is a granular token without access to the target packages. Re-issue a “Automation” token for the org, set both NPM_TOKEN and NODE_AUTH_TOKEN in the workflow, and verify registry-url in setup-node points at https://registry.npmjs.org.
Dependent packages publish a stale version — when package B depends on package A and both are bumped, Turborepo or Nx may rebuild B before A’s new version is on disk. Run changeset version first, then run the build, then run changeset publish. Do not interleave these phases.
changeset add --empty is rejected by changeset version — empty changesets parse fine but do not bump anything. They are useful as a marker for “this PR intentionally needs no version bump” so reviewers know it was considered. If you actually want a version bump, edit the empty file and add the YAML frontmatter manually.
Releases publish but tags do not appear on GitHub — changeset publish only writes git tags when run locally with git available and a writable repository. In the GitHub Action, the changesets/action step handles the tag push, but it requires permissions: contents: write and the default GITHUB_TOKEN must not be restricted by ruleset. Check the repo’s Actions permissions under Settings -> Actions -> General.
Changeset description renders garbled in CHANGELOG.md — markdown special characters (<, >, backticks) inside the changeset body get HTML-escaped by some changelog generators. Use @changesets/changelog-github or wrap code in fenced blocks instead of single backticks if the rendering is consistently off.
For related publishing issues, see Fix: tsup Not Working, Fix: pnpm Peer Dependency Error, Fix: Turborepo Not Working, and Fix: publint Not Working.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: publint Not Working — Package Exports Invalid, Types Not Found, or Dual Package Errors
How to fix publint package validation issues — exports field configuration, dual ESM/CJS packaging, type resolution, main/module/types fields, files array, and common packaging mistakes.
Fix: tsup Not Working — Build Failing, Types Not Generated, or ESM/CJS Output Wrong
How to fix tsup bundler issues — entry points, dual ESM/CJS output, TypeScript declaration files, external dependencies, tree shaking, and package.json exports configuration.
Fix: unbuild Not Working — Build Output Empty, Stub Mode Failing, or Rollup Errors
How to fix unbuild issues — build configuration, stub mode for development, ESM and CJS output, TypeScript declarations, external dependencies, and monorepo workspace builds.
Fix: Clack Not Working — Prompts Not Displaying, Spinners Stuck, or Cancel Not Handled
How to fix @clack/prompts issues — interactive CLI prompts, spinners, multi-select, confirm dialogs, grouped tasks, cancellation handling, and building CLI tools with beautiful output.