A release workflow can pass every test and still ship the wrong package. For maintainers of an existing npm package, a useful upgrade is to let GitHub Actions prepare a release, then require a person to inspect and approve the exact artifact before it becomes public. Here is how to build that checkpoint with npm trusted publishing and staging.

Source check: 26 September 2026. This guide was prepared with AI assistance from the official documentation linked below. The workflow is an illustrative configuration; TechPulse has not executed a live npm release with it. Adapt and validate it for your repository before use.
What changed in npm publishing this month?
On 3 September, npm added multiple trusted-publisher configurations per package. New configurations allow staging by default; direct publishing is optional. Matching any one configuration is sufficient to authorize a release operation, so adding a restrictive entry does not neutralize a permissive one. Staged releases also have to finish npm’s malware scan before approval becomes available. These changes are documented in GitHub’s September announcement.
The practical consequence: review every release path. A carefully gated stable workflow does little if an old prerelease workflow can still publish directly. Treat your list of trusted publishers as a list of independent doors into the package.
Choose the release path your team can operate
| Approach | Best fit | Operational trade-off |
|---|---|---|
| OIDC with staging and human approval | A maintainer can inspect each release | Releases wait for an available reviewer |
| OIDC with direct publishing | A mature automated release process | More responsibility rests on workflow controls |
| Stage-only token | A runner cannot yet use supported OIDC | A stored write credential still needs protection |
Our recommendation for a small project is staging when someone can reliably review it. Put that responsibility in the release checklist, with a backup maintainer where possible. An approval queue nobody owns becomes a release bottleneck, and hurried approvals provide little value.
Check prerequisites before changing CI
The package must already exist on npm, and you need publish access and an account with two-factor authentication enabled. Staging requires npm CLI 11.15.0 or newer and Node.js 22.14.0 or newer. A first-ever package release needs a separate initial-publishing process. These requirements come from npm’s staged-publishing guide.
For the example below, assume one public package at the repository root, a committed lockfile, and a working npm test script. Decide which version and distribution tag you intend to release. Record the expected commit before running anything. If you maintain a monorepo, design package selection explicitly; do not paste a single-package workflow into its root and assume it selects the right workspace.
Connect the exact GitHub workflow to npm
In the package’s trusted-publisher settings, select GitHub Actions and enter the owner, repository and workflow filename, such as release.yml. Use the filename without .github/workflows/. Match any configured environment exactly. Keep direct publishing disabled for this staging approach. Use a GitHub-hosted runner; npm currently excludes self-hosted runners. Check npm’s trusted-publisher instructions when configuring the connection.
OIDC removes the need for a stored npm publishing token in this workflow. It does not decide whether your source code, dependencies or build steps are trustworthy. If your workflow structure needs a refresher, see our guide to GitHub Actions, OIDC and environment rules.
Example: build, inspect and stage
Save an adapted version as .github/workflows/release.yml. The example uses Node 24 and explicitly selects npm 11.20.0, which is available in the official npm registry. Action references are the commit hashes returned by the official repositories’ v6 tags on the source-check date. Review dependency updates through your normal process.
name: Stage npm release
on:
push:
tags:
- 'v*'
permissions:
contents: read
jobs:
stage:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- name: Check out release commit
uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803
with:
persist-credentials: false
- name: Select Node runtime
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38
with:
node-version: '24'
registry-url: 'https://registry.npmjs.org'
package-manager-cache: false
- name: Select npm CLI
run: npm install --global npm@11.20.0 --ignore-scripts
- name: Install locked dependencies
run: npm ci
- name: Build package
run: npm run build --if-present
- name: Run project tests
run: npm test
- name: Inspect package file list
run: npm pack --dry-run --ignore-scripts
- name: Stage for maintainer review
run: npm stage publish
The checkout and setup-node repositories document these action inputs. No publishing secret is supplied. This example assumes public dependencies; private dependencies need a separately scoped installation credential. The final command stages a real package version, so use it only when you intend to prepare that release.
npm pack --dry-run --ignore-scripts shows the proposed file list without running package lifecycle scripts for that inspection. It does not prove that later lifecycle hooks leave the artifact unchanged. Review the tarball that npm actually staged, too. See the npm pack reference for these flags.
Review the artifact, not just the green checkmark
Use an authenticated maintainer session to identify the staged release and download its tarball. Replace the example package name and stage ID. The npm stage reference documents these commands; staging is separate from approval.
npm stage list @your-scope/your-package
npm stage view <stage-id>
npm stage download <stage-id>
Our proposed review record has five checks. Keep it with the release issue so the next maintainer can understand the decision:
- Identity: Do package name, version, intended distribution tag and release commit match the release request?
- Contents: Are expected compiled files present? Are private configuration files, credentials, local databases or unrelated artifacts absent?
- Behavior: Did installation scripts, executable entry points or dependencies change? Can you explain each change?
- Reproducibility: Can the recorded source and build instructions account for the artifact? Investigate unexplained generated-code changes before approval.
- Decision: Record who reviewed the release and any remaining limits. A scanner’s completed status does not replace this judgment.
Inspect unfamiliar tarballs in an isolated location without executing their scripts. After review, npm stage approve <stage-id> publishes that staged version and requires 2FA. Keep approval in the human process, outside the CI workflow. A staged version also occupies its version number; check the queue before rerunning a failed release.
Protect the workflow that creates the package
GitHub recommends pinning actions to full commit hashes and reviewing their source. Require review for workflow changes, limit repository permissions and control who can create release tags. Its secure-use reference explains why a compromised action can affect other work in the job.
Make the reviewer’s job small enough to do well. A focused release with a short change list is easier to inspect than a month of unrelated changes bundled into one approval. If tests pass but the packaged files look surprising, stop at staging and investigate; rerunning the job is not an explanation.
Migrate without losing your release path
Verify the new trust connection first. Then restrict traditional token publishing in npm’s package settings and revoke obsolete publish tokens. Authentication failures commonly come from mismatched repository or workflow details, missing id-token: write, or unsupported runners. npm whoami does not confirm OIDC status; authentication happens during staging or publishing. Use the official troubleshooting and migration guidance.
If OIDC is unavailable in your environment, npm introduced stage-only granular tokens on 18 September. They cannot publish new versions directly, but retain other write powers, including dist-tag changes and deprecation. Existing tokens are not automatically converted. npm is targeting January 2027 for removal of direct publishing through bypass-2FA tokens; that is a stated target, not a change already completed. See the stage-only token announcement.
The useful outcome is a release you can trace: an intended source revision, a known artifact, and a recorded approval. Start with one existing package, prove that sequence, and then extend it to the rest of your projects.
✍️ Leave a Comment