Skip to main content

setup-github-npm-publish

Publish an npm package automatically from GitHub Actions when a semver tag is pushed, using npm trusted publishing (OIDC) instead of an NPM_TOKEN. Use when setting up or fixing automatic npm releases, including the one-time trusted publisher setup and the first publish.

Source facts

Repository
dvcrn/skills
Last source activity
October 21, 2026 at 12:01
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

File Explorer
3 files

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
setup-github-npm-publish
description
Publish an npm package automatically from GitHub Actions when a semver tag is pushed, using npm trusted publishing (OIDC) instead of an NPM_TOKEN. Use when setting up or fixing automatic npm releases, including the one-time trusted publisher setup and the first publish.
# Publish to npm from a git tag A tag like `1.2.3` publishes the package with that version. GitHub's OIDC token authenticates the publish, so no npm token is stored in the repo, and npm records provenance. ## 1. Extend the existing release flow first Look in `.github/workflows/` for a workflow that already runs on tags, e.g. the `release.yml` from `setup-goreleaser`. If there is one, add an `npm` job to it with `needs:` on the job that must finish first, and add `id-token: write` to its permissions. Create a separate workflow only when nothing runs on tags. One tag should start one run: two workflows on the same tag cannot depend on each other, so npm could publish a wrapper whose binaries are not uploaded yet. ## 2. Choose the variant **Package in a subdirectory, version from the tag** (Go binary wrappers from `setup-golang-npm-publish`): append `assets/npm-job-subdir.yml` under `jobs:`. The job declares its own `id-token: write`, because the GoReleaser job only needs `contents: write`. `package.json` keeps a placeholder version; the job runs `npm version <tag>` before publishing. **Package at the root, version in package.json** (TypeScript and other npm-native projects): use `assets/publish-root.yml`. The job fails unless the tag equals the `package.json` version, so bump the version and tag together. Both need: - `permissions: id-token: write` (plus `contents: write` if the same workflow creates a GitHub release). - `actions/setup-node` with `registry-url: https://registry.npmjs.org`. Trusted publishing needs npm 11.5.1+ and Node 22.14+; use Node 24. - `repository.url` in `package.json` exactly matching the GitHub repo, e.g. `git+https://github.com/<owner>/<repo>.git`. - No `NODE_AUTH_TOKEN` or `NPM_TOKEN` secret. ## 3. One-time npm setup npm only accepts a trusted publisher for a package that already exists, so the first version is published by hand. Publish a minimal placeholder, not the real package: a wrapper's install script would fail for anyone installing it before its release exists. ```sh mkdir -p /tmp/npm-placeholder && cd /tmp/npm-placeholder cat > package.json <<'EOF' { "name": "<package>", "version": "0.0.0-placeholder", "description": "Placeholder; releases are published from CI", "repository": { "type": "git", "url": "git+https://github.com/<owner>/<repo>.git" } } EOF npm login npm publish --access public --tag placeholder ``` Then add the trusted publisher, either in the package settings on npmjs.com (GitHub Actions, owner, repo, workflow filename) or with npm 11.15.0+: ```sh npm trust github <package> --repository <owner>/<repo> --file <workflow>.yml --allow-publish ``` Both ask for 2FA. **A new trusted publisher must complete its first successful publish within 2 days**, so tag a release soon after. ## Pitfalls - **Do not publish the version you are about to tag by hand.** CI then fails with "You cannot publish over the previously published versions". If it happened, the package is fine; tag the next patch version to prove CI publishing works. - The workflow filename registered on npm must match the file that runs the publish, including after renames. - Tag patterns: plain `1.2.3` matches `"[0-9]*.[0-9]*.[0-9]*"`; `v1.2.3` needs `"v[0-9]*.[0-9]*.[0-9]*"` and stripping the `v`. ## Verify a release ```sh gh run list --limit 3 gh run view <run-id> --log-failed npm view <package> versions time --json npm view <package>@<version> dist.attestations --json # present only when CI published it through OIDC ```
View on GitHub