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
| Requirement | Detail |
|---|---|
| CI provider | GitHub Actions or GitLab CI/CD, on cloud hosted runners |
| npm CLI | 9.5.0 or later |
| package.json | A public repository field that matches the publishing repository, case sensitive |
| GitHub permission | id-token write |
| First publish of a scoped public package | Add 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
- Repository field mismatch is the usual failure. Copy the exact URL.
- Missing id-token write on the job.
- Self hosted or unsupported runner.
- Old npm CLI. Print the version in the workflow.
- 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.