changesets/action
> GitHub Action that turns pending changeset files into an auto-maintained "Version Packages" PR — merge the PR to version, changelog, and publish your packages to npm.
GitHub repo · Official website · License: MIT
Overview
changesets/action is the CI half of the Changesets release workflow for JavaScript/TypeScript repos, especially multi-package monorepos. Contributors commit small markdown "changeset" files declaring intent ("bump @scope/pkg minor: added X"); this action, running on every push to the base branch, collects them into a single pull request with all version bumps and changelog entries applied. Merging that PR triggers the same action to publish to npm, push git tags, and create GitHub releases1. The repo dates to August 2019 and remains actively maintained (pushed this week); at ~1,000 stars the count badly understates adoption — as a CI dependency it sits in the release pipelines of much of the JS monorepo ecosystem (pnpm, emotion, XState, and most Changesets-org-adjacent projects), where nobody stars the action itself.
The design's defining tension: it drives releases through GitHub's PR model using GitHub's own token, and GitHub deliberately prevents GITHUB_TOKEN-created commits and PRs from triggering other workflows. So the Version Packages PR the action opens gets no CI runs by default — the single most common operational surprise, with a well-worn workaround (PAT or GitHub App token) that shifts secret-management burden onto you.
Versioning is currently split: the v1 line (stable, maintenance/v1 branch) targets Changesets v2, while main is the in-progress v2 targeting Changesets v3, published only as v2.0.0-next.* prereleases as of mid-20262. The v2 rewrite renames all inputs to kebab-case (publish → publish-script, version → version-script), so examples on the internet are split between two incompatible input schemas.
Getting Started
Requires an existing Changesets setup (npx changeset init creates .changeset/). Then add .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@v6
- uses: actions/setup-node@v6
with:
node-version: 26
- run: npm ci
- name: Create Release PR or Publish
id: changesets
uses: changesets/action@v1
with:
publish: npx changeset publish # v2 prerelease: `publish-script:`
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
The NPM_TOKEN must be able to publish without 2FA-on-publish (an npm automation/granular token)1.
Architecture / How It Works
The action is a TypeScript program with one branching decision, evaluated on every push to the base branch:
1. Changesets pending (.changeset/*.md files exist): run changeset version (or your version script), which consumes the changeset files, bumps package.json versions across the monorepo, and rewrites changelogs. The result is committed to a changeset-release/<branch> branch, force-pushed, and an open "Version Packages" PR is created or updated. The PR body aggregates the pending changelog entries. 2. No changesets pending and a publish script is configured: assume a Version Packages PR was just merged, run the publish script (conventionally changeset publish, which skips already-published versions), then push git tags and create GitHub releases for each published package, and expose published / published-packages outputs for downstream steps (notifications, deploys)1.
The action itself contains no versioning logic — semver math, changelog generation, and inter-package dependency bumping all live in the changesets CLI it shells out to. This keeps the action thin but couples its major versions to Changesets major versions (v1↔Changesets v2, v2↔Changesets v3)2.
Notable knobs: commit-mode: github-api routes commits/tags through the GitHub API instead of git CLI, producing GPG-signed commits attributed to the token owner (needed for orgs enforcing signed commits); pr-draft controls draft-PR behavior; the action writes an ~/.npmrc with NPM_TOKEN unless one already exists. Two sub-actions live in the same repo: pr-status (changeset status reporting in PRs) and pr-comment1.
Production Notes
The Version Packages PR gets no CI. With the default GITHUB_TOKEN, GitHub suppresses workflow triggers on the PR the action creates3. Teams routinely merge release PRs that were never tested. Fixes: pass a PAT or GitHub App installation token as github-token, or trigger CI on push to changeset-release/**. Budget for token rotation either way.
Permissions. Under GitHub's restricted default token permissions you must grant contents: write and pull-requests: write, or the action fails with an unhelpful 403. commit-mode: github-api plus GitHub releases also needs the token to create releases.
Race conditions. Two pushes to main in quick succession can run the publish path concurrently. The README's concurrency: ${{ github.workflow }}-${{ github.ref }} line is not decoration — omit it and you will eventually see duplicate-publish errors. Relatedly, a changeset-free commit landing after a publish re-enters the publish branch; changeset publish tolerates this (skips existing versions), but custom publish scripts must be idempotent1.
Force-push semantics. The changeset-release/* branch is force-pushed on every base-branch push. Manual edits to the release PR branch (e.g., hand-tuning a changelog) are silently destroyed the next time anyone merges to main. Edit the changeset files on main instead.
Changelog generators need the token in env. @changesets/changelog-github (the common choice, links PRs/authors) reads GITHUB_TOKEN from the environment of the version step; forgetting it fails the version run.
Maintenance cadence. Release history shows long quiet stretches (one patch release in all of 2024's mid-year, v1.4.7→v1.4.9) followed by a marked 2026 revival: v1.6.0 through v1.9.0 shipped January–June 2026 alongside the v2 prerelease push2. 120 open issues reflect a small-maintainer-team project carrying a large user base, not abandonment.
Pinning. @v1/@v2 are floating tags. Security-sensitive repos should pin to a commit SHA — this action handles your npm credentials.
When to Use / When Not
Use when:
- You run a JS/TS monorepo publishing multiple interdependent npm packages and already use (or want) Changesets' contributor-authored release notes.
- You want a human review gate (the Version Packages PR) between "code merged" and "version published".
- You want batched releases: many merged PRs → one version PR → one publish.
Avoid when:
- You want zero-touch per-commit releases from commit messages — semantic-release's model, no PR gate, no changeset files.
- Your packages are not npm/JS: Changesets is JS-ecosystem-specific; release-please covers many languages.
- You need immediate publishes; the PR-gate model adds a human merge step by design.
- Your team won't reliably write changeset files — the whole pipeline silently does nothing without them (the
pr-statussub-action or the changeset-bot mitigates this).
Alternatives
- googleapis/release-please — same release-PR model, conventional-commit-driven and multi-language; use it outside the JS/Changesets ecosystem or when commit messages should drive versioning.
- semantic-release/semantic-release — fully automated publish on every qualifying commit, no review gate; use when you want releases with zero human steps.
- intuit/auto — label-driven releases from PR labels; use when PR metadata, not files or commit syntax, should decide bumps.
- lerna/lerna — older monorepo versioning/publishing (
lerna version/lerna publish); use for legacy Lerna repos not worth migrating.
History
| Version | Date | Notes |
|---|---|---|
| — | 2019-08 | Repo created; pre-1.0 usage via @master. |
| v1.0.0 | 2021-11-25 | First tagged stable release2. |
| v1.4.0 | 2022-11-02 | v1 line matures; slow-cadence maintenance era begins. |
| v1.4.9 | 2024-10-14 | One of only three releases across 2024 — quietest period. |
| v1.5.0 | 2025-05-05 | Maintenance resumes; rapid 1.5.x patch series in May 2025. |
| v1.6.0–v1.9.0 | 2026-01 → 2026-06 | Active 2026 feature cadence on the v1 line2. |
| v2.0.0-next.0 | 2026-06-23 | Changesets v3 compatibility; kebab-case input renames; v1 moves to maintenance/v12. |
References
- ^ changesets/action README (main branch). https://github.com/changesets/action#readme
- ^ changesets/action releases (tag dates). https://github.com/changesets/action/releases
- ^ GitHub Docs, "Triggering a workflow from a workflow" — events from
GITHUB_TOKENdo not create new workflow runs. https://docs.github.com/en/actions/using-workflows/triggering-a-workflow#triggering-a-workflow-from-a-workflow
Tags
github-actions, typescript, release-automation, versioning, changelog, monorepo, npm-publishing, ci-cd, semver, javascript