Safeguard
Supply Chain•

How do you publish an npm package with provenance on GitHub?

Publish with npm provenance from GitHub Actions: grant id-token write, use a hosted runner, match the repository field, and use the provenance flag.

Safeguard Security Team
3 min read

To publish an npm package with provenance, build in GitHub Actions on a GitHub hosted runner, grant the job id-token write permission, make sure the repository field in package.json matches your repo exactly, and run npm publish with the provenance flag. npm CLI 9.5.0 or later is required.

What you get

Provenance links a published version to the place it was built and published. It tells consumers which repository and workflow produced the package. It does not tell them the code is safe. Read what package provenance proves and what it does not before you describe it to users.

Requirements from the npm docs

RequirementDetail
CI providerGitHub Actions or GitLab CI/CD, on cloud hosted runners
npm CLI9.5.0 or later
package.jsonA public repository field that matches the publishing repository, case sensitive
GitHub permissionid-token write
First publish of a scoped public packageAdd the public access flag

The npm documentation does not address self hosted runners explicitly; it only requires cloud hosted ones, so test before you rely on them.

A minimal workflow

name: Release
on:
  push:
    tags: ["v*"]
jobs:
  publish:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v5
        with:
          persist-credentials: false
      - uses: actions/setup-node@v5
        with:
          node-version: 24
          registry-url: https://registry.npmjs.org
      - run: npm ci
      - run: npm publish --provenance --access public
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

The token here is a stand in for the older style. If you move to trusted publishing, you can drop the token entirely.

Other ways to switch provenance on

If a tool calls npm for you, the docs list three alternatives: set the environment variable NPM_CONFIG_PROVENANCE to true, add "provenance": true under publishConfig in package.json, or add provenance=true to .npmrc. Yarn needs version 4.9.0 or later.

Trusted publishing makes it automatic

The trusted publishing page says provenance is generated automatically for GitHub Actions and GitLab publishes from public repositories of public packages, with no flag needed, and not generated for CircleCI or private repositories. You can disable it with provenance=false. See npm versus PyPI trusted publishing.

One gotcha from the npm publish docs: if you pass a provenance file yourself, it takes precedence, and automatic provenance generation, including trusted publishing through OIDC, is skipped.

Troubleshooting checklist

  1. Repository field mismatch is the usual failure. Copy the exact URL.
  2. Missing id-token write on the job.
  3. Self hosted or unsupported runner.
  4. Old npm CLI. Print the version in the workflow.
  5. Preview contents first with a dry run of npm pack, as in check what you are about to publish.

Safeguard can generate an SBOM and scan the dependencies you publish with; the free scan at gold.safeguard.sh/scan is a quick start.

Quick check

Does provenance work for a private repository?

Trusted publishing does not generate it for private repositories, per npm's page. Check the docs for your exact case.

Can the same package publish with and without provenance?

Yes. It is set per publish, so versions published without it simply lack the statement.

Sources

Last reviewed: 19 October 2026.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.