Skip to content

GitHub Actions

Use this recipe to run semantic-release on GitHub Actions with a secure default setup. It covers authentication options, trusted publishing with OIDC and npm provenance, a minimal release workflow for Node projects, and common pitfalls to avoid when configuring npm and GitHub tokens.

  1. Create .github/workflows/verify-and-release.yml using the verify-and-release workflow configuration.
  2. Choose a publishing path.
  3. Push a commit to main/master (or run workflow_dispatch) and verify with the Release readiness checklist. For manual runs, see Trigger semantic-release on demand.
Section titled “Path A (recommended): Trusted publishing (OIDC)”
  • No long-lived npm token in GitHub secrets.
  • npm provenance is generated automatically.
  • Requires id-token: write permission in the job that runs semantic-release.
  • Requires an npm Trusted Publisher configured for the workflow that triggers the run.
  • Add NPM_TOKEN to repository or organization secrets.
  • Keep GITHUB_TOKEN for GitHub release notes, issue comments, and pull request comments.
  • Use this only when trusted publishing is not available for your setup.

GitHub Actions supports workflows, allowing you to run tests on multiple Node versions and publish a release only when all tests pass.

.github/workflows/verify-and-release.yml configuration for Node projects

Section titled “.github/workflows/verify-and-release.yml configuration for Node projects”

Use this as a starting point for .github/workflows/verify-and-release.yml. This example runs verification first and only runs semantic-release if verification succeeds. Make sure to adjust the trigger and branch name as needed. The example below is configured for trusted publishing with OIDC, but it can be easily adapted to use NPM_TOKEN instead by removing the id-token: write permission and ensuring NPM_TOKEN is available in secrets.

name: Verify and Release
on:
push:
branches:
- main # or master
permissions:
contents: read # for checkout
jobs:
verify:
name: Verify
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
- name: Run tests
run: npm test
release:
name: Release
runs-on: ubuntu-latest
needs: verify
permissions:
contents: write # to be able to publish a GitHub release
issues: write # to be able to comment on released issues
pull-requests: write # to be able to comment on released pull requests
id-token: write # to enable use of OIDC for trusted publishing and npm provenance
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Verify the integrity of provenance attestations and registry signatures for installed dependencies
run: npm audit signatures
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: npx semantic-release # <- The Run Commnand

The workflow above shows a verify-then-release setup with the default semantic-release flow. If your release process needs a different invocation style or non-default behavior (for example, plugins or shareable configurations), refer to Running semantic-release.

The Authentication environment variables can be configured with GitHub Actions secrets.

If you are not using trusted publishing, an NPM_TOKEN is required to publish a package to the npm registry. GitHub Actions automatically populates a GITHUB_TOKEN environment variable that can be used in workflows.

For improved security and automation, it is recommended to leverage trusted publishing through OpenID Connect (OIDC) when publishing to npm from GitHub Actions. GitHub Actions is a trusted identity provider for npm, enabling configuration of a trust relationship between your GitHub repository and npm so that no long-lived secret (like an NPM_TOKEN) is required to publish packages to npm from GitHub Actions. The npm registry recently increased restrictions for use of long-lived access tokens, further encouraging trusted publishing as the preferred approach for publishing to npm from GitHub Actions. Enabling trusted publishing requires granting the id-token: write permission to the job performing the publish step and configuring a trust relationship between your GitHub repository and npm.

npm provenance is valuable for increasing supply-chain security for your npm packages. Before trusted publishing was available, generating provenance attestations required configuring your project to enable publishing with provenance. With trusted publishing, npm provenance is automatically generated for packages published to npm from GitHub Actions without any additional configuration.

  • Do not set registry-url in actions/setup-node when using semantic-release for npm publishing. It creates an .npmrc that can conflict with semantic-release auth and lead to EINVALIDNPMTOKEN errors.
  • If you need a custom npm registry, set it in your project .npmrc.
  • If using npm trusted publishing, keep id-token: write permission in the release job.
  • If using NPM_TOKEN, ensure it is configured as a repository or organization secret.
# ❌ Don't do this - can cause conflicts with semantic-release
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
registry-url: "https://registry.npmjs.org"
# ✅ Do this instead - let semantic-release handle registry configuration through normal npm conventions
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"

Pushing package.json changes to your repository

Section titled “Pushing package.json changes to your repository”

If you choose to commit changes to your package.json against our recommendation, the @semantic-release/git plugin can be used.

Example release job using GitHub App authentication with @semantic-release/git (assuming a preceding verify job):

# verify:
# # ... your existing verify job
release:
name: Release
runs-on: ubuntu-latest
needs: verify
permissions:
contents: write
issues: write
pull-requests: write
id-token: write
steps:
- name: Create GitHub App token
id: app-token
uses: actions/create-github-app-token@v1
with:
app-id: ${{ vars.RELEASE_APP_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ steps.app-token.outputs.token }}
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "lts/*"
- name: Install dependencies
run: npm clean-install
- name: Release
env:
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
run: npx semantic-release
  • Your workflow triggers on the branch you release from (main or master).
  • fetch-depth: 0 is enabled in checkout.
  • GITHUB_TOKEN is available to semantic-release for the default release flow.
  • If you commit files during release on a protected branch (for example with @semantic-release/git), GitHub App auth is configured and checkout uses the app token.
  • You chose one npm auth path: trusted publishing (id-token: write) or NPM_TOKEN secret.
  • registry-url is not set in actions/setup-node.
  • Your runtime meets the supported Node version policy.

Use these options when you want to trigger a release outside the normal push-based workflow.

You can use workflow_dispatch to run the release workflow manually from the GitHub UI.

Use the repository_dispatch event to control when to generate a release by making an HTTP request, for example:

name: Release
on:
repository_dispatch:
types: [semantic-release]
jobs:
# ...

To trigger a release, call the GitHub API with a Personal Access Token stored in the GITHUB_TOKEN environment variable:

$ curl -v -X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer ${GITHUB_TOKEN}" \
-H "X-GitHub-Api-Version: 2022-11-28" \
https://api.github.com/repos/[org-name-or-username]/[repository]/dispatches \
-d '{ "event_type": "semantic-release" }'