Skip to main content
Technology & EngineeringMonorepo205 lines

Changesets

Versioning and changelog management with Changesets for coordinated monorepo package releases

Quick Summary29 lines
You are an expert in Changesets for managing versioning, changelogs, and publishing across monorepo packages.

## Key Points

- **`linked`** — Packages that should always have the same version. If one bumps major, they all bump major.
- **`fixed`** — Packages that always share the exact same version number.
- **`access`** — `"public"` for scoped packages on npm, `"restricted"` for private.
- **`updateInternalDependencies`** — Automatically bump internal consumers when a dependency changes.
- **`ignore`** — Packages excluded from versioning (docs sites, dev tools).
1. Which packages have changed?
2. Is each change major, minor, or patch?
3. Provide a summary of the change.
- Bumps `version` in each affected `package.json`
- Updates `CHANGELOG.md` in each package
- Removes consumed changeset files
- Updates internal dependency ranges

## Quick Example

```bash
pnpm add -D @changesets/cli
pnpm changeset init
```

```bash
pnpm changeset
```
skilldb get monorepo-skills/ChangesetsFull skill: 205 lines
Paste into your CLAUDE.md or agent config

Changesets — Monorepo Management

You are an expert in Changesets for managing versioning, changelogs, and publishing across monorepo packages.

Core Philosophy

Overview

Changesets is a versioning and release tool designed for monorepos. It allows developers to declare their intent to release (a "changeset") alongside their code changes. At release time, Changesets aggregates all pending changesets, bumps versions according to semver, updates changelogs, and publishes packages. This decouples "deciding what changed" from "performing the release."

Setup & Configuration

Installation

pnpm add -D @changesets/cli
pnpm changeset init

This creates a .changeset/ directory with a config.json.

.changeset/config.json

{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [["@myorg/ui", "@myorg/ui-icons"]],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": ["@myorg/docs", "@myorg/storybook"],
  "privatePackages": {
    "version": true,
    "tag": false
  }
}

Key Configuration Options

  • linked — Packages that should always have the same version. If one bumps major, they all bump major.
  • fixed — Packages that always share the exact same version number.
  • access"public" for scoped packages on npm, "restricted" for private.
  • updateInternalDependencies — Automatically bump internal consumers when a dependency changes.
  • ignore — Packages excluded from versioning (docs sites, dev tools).

Core Patterns

Creating a Changeset

pnpm changeset

This interactive prompt asks:

  1. Which packages have changed?
  2. Is each change major, minor, or patch?
  3. Provide a summary of the change.

It creates a markdown file in .changeset/:

---
"@myorg/ui": minor
"@myorg/utils": patch
---

Added new Button variant and updated utility helpers for color tokens.

Versioning Packages

pnpm changeset version

This consumes all pending changeset files and:

  • Bumps version in each affected package.json
  • Updates CHANGELOG.md in each package
  • Removes consumed changeset files
  • Updates internal dependency ranges

Publishing

pnpm changeset publish

Publishes all packages with new versions to the registry. Packages that haven't changed are skipped.

CI Automation with GitHub Actions

name: Release
on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile
      - run: pnpm run build

      - name: Create Release PR or Publish
        uses: changesets/action@v1
        with:
          publish: pnpm changeset publish
          version: pnpm changeset version
          title: 'chore: version packages'
          commit: 'chore: version packages'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

The changesets/action creates a "Version Packages" PR that stays up to date. Merging it triggers the publish step.

Snapshot Releases

For pre-release testing without full version bumps:

# Create a snapshot release
pnpm changeset version --snapshot canary
pnpm changeset publish --tag canary --no-git-tag

# Produces versions like 1.2.3-canary-20240315120000

Pre-releases

# Enter pre-release mode
pnpm changeset pre enter beta

# Create changesets and version as usual
pnpm changeset
pnpm changeset version
# Produces versions like 1.2.0-beta.0

# Exit pre-release mode when ready
pnpm changeset pre exit
pnpm changeset version
# Produces the stable version 1.2.0

Custom Changelog Generation

{
  "changelog": [
    "@changesets/changelog-github",
    { "repo": "myorg/myrepo" }
  ]
}

This links PRs and authors in the generated changelog entries.

Best Practices

  1. Require changesets in PRs — Use the Changesets bot or a CI check to ensure every user-facing PR includes a changeset.
  2. Write user-facing summaries — Changeset descriptions become changelog entries. Write them for consumers, not developers.
  3. Use linked for tightly coupled packages — UI component packages that must stay in sync should be linked.
  4. Use ignore for private packages — Docs sites, example apps, and dev tools don't need versioning.
  5. Automate with the GitHub Action — The Changesets GitHub Action handles the version PR and publish flow automatically.
  6. Use snapshot releases for testing — Publish canary versions from feature branches so consumers can test before merge.
  7. Review version PRs carefully — The aggregated version PR shows all version bumps and changelog entries; review it for accuracy.

Common Pitfalls

  • Forgetting to add a changeset — PRs merged without changesets won't be included in the next release. Enforce with CI checks.
  • Wrong semver level — A breaking API change marked as patch will surprise consumers. Review changeset semver levels in code review.
  • Internal dependency cascades — With updateInternalDependencies: "patch", changing one package can trigger version bumps across many packages. This is correct but can be surprising.
  • Not building before publishchangeset publish runs npm publish which uses the files field. Ensure dist/ is built and up to date.
  • Pre-release mode confusion — Forgetting to exit pre-release mode means all subsequent versions will be pre-releases. Always changeset pre exit before the stable release.

Anti-Patterns

Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.

Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.

Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.

Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.

Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.

Install this skill directly: skilldb add monorepo-skills

Get CLI access →