astradevlabsastradevlabs
← All posts
Dev Tips4 min

Ranked List: 7 Checks Before Splitting npm Trusted Publishing Across Workflows

Dev Tips

npm quietly removed a release-engineering constraint on September 3, 2026: one package can now have multiple trusted publishing configurations. Stable, prerelease, and staging workflows no longer need to share one OIDC identity—or fall back to a long-lived write token.

That flexibility is useful, but additive trust is easy to misunderstand. npm authorizes a publish when the incoming OIDC token matches any configured publisher. Configurations do not narrow one another, and their evaluation order is not guaranteed. Treat every added workflow as another independent route to your package.

Here are the seven checks worth making before you split that route.

7. Confirm the runner and toolchain are eligible

Start with the boring compatibility gate. npm trusted publishing currently supports GitHub-hosted Actions runners, GitLab.com shared runners, and CircleCI cloud. Self-hosted runners are not supported. npm's trusted-publisher guide also requires npm CLI 11.5.1 or later and Node.js 22.14.0 or later. Staged publishing has a higher CLI floor: npm 11.15.0.

Check the versions inside the release job, not on your laptop:

sh
node --version
npm --version

If the job misses either floor, fix that before editing registry settings. Otherwise an authentication failure can look like a bad trust configuration when the runner was never eligible.

6. Give each release lane its own exact identity

A trusted publisher is matched against provider-specific claims: repository, workflow file, and optionally an environment for GitHub Actions. The workflow filename must include .yml or .yaml, live under .github/workflows/, and match exactly.

Use that precision. A package with stable.yml, prerelease.yml, and stage.yml should get three explicit configurations rather than one workflow full of branch-dependent release logic. npm allows up to ten trusted publishers per package, so there is room to represent real release lanes directly.

This is also the moment to delete abandoned configurations. Multiple entries are additive; an old workflow is still an authorization path until you remove it. Existing entries cannot be edited, so replace a wrong one by deleting and recreating it.

5. Keep OIDC permission local to the publish job

GitHub Actions needs id-token: write to request the short-lived OIDC token. That permission does not itself grant write access to npm or your repository, but it should still sit on the smallest useful scope: the job that publishes.

yaml
jobs:
  release:
    permissions:
      contents: read
      id-token: write
    runs-on: ubuntu-latest

For reusable workflows, verify both ends. npm documents that validation can use the calling workflow's name, and GitHub requires explicit OIDC permission at the caller when the reusable workflow lives outside your organization or enterprise. A neat shared workflow does not help if the identity reaching npm differs from the filename you registered.

4. Default every new lane to stage-only

Every trusted publisher can run npm stage publish by default; direct npm publish is an opt-in permission per configuration. That default is the safer choice. Staging uploads the package without making it public, then requires a maintainer to approve it with 2FA.

The September 3 update makes this gate stronger operationally: npm now disables approval until its malware scan completes, and maintainers can see whether a version was staged, approved, or rejected in package history.

Reserve direct publishing for the lane where automation genuinely must complete unattended. A prerelease channel may justify that tradeoff. Your stable channel often does not.

3. Test the package identity, not only the workflow

OIDC removes the secret, not the need for exact metadata. For GitHub publishing, the package's repository.url must match the repository registered with npm, including case. Public provenance also depends on a public repository and public package.

Before the first real release, inspect what will ship:

sh
npm pack --dry-run
npm pkg get name version repository

This catches the surprisingly common failures: publishing from the wrong workspace, a stale repository URL after a transfer, or a package name that points at a different registry record.

2. Prove each lane with a harmless version

Do not switch three workflows and discover their claim mismatches during a production release. Exercise each configuration independently with a disposable prerelease version and an explicit non-latest tag. Staged versions consume the same unique semver slot as published versions, so choose versions you are prepared to approve or reject.

For stage-only lanes, download and inspect the staged tarball before approval. That tests the full chain: build output, package contents, OIDC exchange, registry matching, malware scan, and human promotion. A green CI job alone proves less.

1. Remove the token only after OIDC succeeds

The safest migration order is intentionally unexciting: add the trusted publishers, verify each workflow, then set package publishing access to require 2FA and disallow tokens, and finally revoke obsolete automation tokens.

Private dependencies are the exception that often confuses teams. Trusted publishing authenticates the publish operation; it does not authenticate npm ci. If the release build installs private packages, retain a granular read-only token for installation while keeping publication on OIDC.

The new multi-configuration model is not permission composition. It is a set of independent doors. Name each door after a real release lane, keep most of them stage-only, test them separately, and close the old token entrance last.

References