Skip to content
Latchkey

How to Release a Monorepo With the Changesets Flow in CI

Changesets separates intent (a changeset file) from action (version and publish), so CI can accumulate intents and release in one atomic step.

Contributors run changeset add to drop a markdown intent file under .changeset/. In CI, changeset version consumes those files to bump package.json versions and write changelogs, and changeset publish pushes the bumped packages to the registry.

Steps

  • Install @changesets/cli and run changeset init to create .changeset/config.json.
  • On each PR, run changeset add to record which packages changed and at what semver level.
  • In CI on main, run changeset version to apply the pending changesets.
  • Run changeset publish to publish every package whose version increased.

Manual flow

Terminal
# On a feature branch: describe the change
pnpm changeset

# In CI on main: apply pending changesets
pnpm changeset version   # bumps package.json + writes CHANGELOG.md
git add -A && git commit -m "Version packages"

# Publish the newly bumped packages
pnpm changeset publish    # runs npm publish for each changed package

Publish workflow

.github/workflows/release.yml
on:
  push:
    branches: [main]
jobs:
  release:
    runs-on: ubuntu-latest
    permissions:
      contents: write
      id-token: write
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          registry-url: https://registry.npmjs.org
      - run: pnpm install --frozen-lockfile
      - run: pnpm changeset publish
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

Gotchas

  • changeset publish publishes only packages whose version in package.json is ahead of the registry, so it is safe to re-run.
  • Run changeset version and commit before changeset publish; publishing without bumping does nothing.

Related guides

Run this faster and cheaper on Latchkey managed runners. Start free →