Use Changesets to manage version numbers, combined with GitHub OIDC credentials to directly publish to npmjs.com. The entire process requires no manual npm token configuration, making it secure and automated.

Core Configuration Key Points

1. Configure Trusted Publisher on npmjs.com

On npmjs.com → your published package → Settings → Add GitHub repository to associate the package with the GitHub repository. After that, you can automatically publish via OIDC.

2. Allow Changesets to Create PRs in GitHub

In GitHub repo → Settings → Actions → General → Workflow permissions, check Read and write permissions, and also check Allow GitHub Actions to create and pull requests.

3. Key package.json Configuration

{
  "packageManager": "pnpm@9.15.0",
  "publishConfig": {
    "access": "public"
  },
  "scripts": {
    "release": "pnpm run build && changeset publish"
  }
}

Note: The release script cannot be named publish, otherwise it will execute twice.

4. GitHub Workflow Example

  • Node version must be greater than 22 to support OIDC.
# .github/workflows/publish.yml
name: Publish Package
on:
  push:
    branches:
      - main

permissions:
  contents: write
  pull-requests: write # for Changesets to create PRs
  id-token: write
  deployments: write

concurrency: ${{ github.workflow }}-${{ github.ref }} # prevent duplicate publishing, new action runs only after the old one completes

jobs:
  release:
    name: Release & Publish
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0 # required for Changesets to calculate changes
      - uses: pnpm/action-setup@v3
      - uses: actions/setup-node@v4
        with:
          node-version: 24 # must be greater than 22 to support OIDC
          cache: "pnpm"
          registry-url: "https://registry.npmjs.org"
      - run: pnpm install --frozen-lockfile
      - name: Create Release PR or Publish
        id: changesets
        uses: changesets/action@v1
        with:
          publish: pnpm release
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # for write repo