Npm Publishing
Overview
Use this skill to make a repo publish-ready and to publish it safely with a short, repeatable workflow.
Prefer the smallest set of changes that gets the package publishable. Keep package contents explicit, verify the tarball before publish, and treat auth and org permissions as separate from package configuration.
Workflow
Inspect the package root. Read
package.json, check the intended entry point, and inspect the folders that should ship. Ifsemantic-releaseis configured, check for a dedicated release config file such as.releaserc.jsand treat that as the source of truth over older inline config examples.Align package metadata with the intended publish target. Ensure the scoped package name is correct. Set
"private": falsewhen the package must publish. Add"publishConfig": { "access": "public" }for public scoped packages. Setmainorexportsto a real entry file. Add afilesarray when the package should publish only selected paths.Protect secrets and local publish config. Ignore
.envfiles in.gitignore. Prefer readingNPM_TOKENfrom a local.envfile instead of hardcoding credentials inpackage.json.Add or update repo-local publish commands. If the repo needs a reusable publish flow, add a small Node script rather than a long inline one-liner in
package.json. Keep the script at a stable path such as./scripts/publish-public-w-local-token.cjs. Prefer a temporary npm config file over passing the token on the command line. Use the helper at scripts/publish-with-local-token.cjs as the starting point when the repo does not already have its own version.Verify publish contents before release. Run
npm pack --dry-runor the repo's equivalent script. Confirm the tarball includes the intended files and excludes local secrets or unrelated workspace files.Choose the publish mode. For one-off local publishing, use a repo-local helper that reads
NPM_TOKENfrom.env. For automated publishing from GitHub, prefersemantic-releaseon pushes tomain. Do not configure npm caching inactions/setup-nodefor the release workflow. When the repo already usessemantic-release, preserve the existing config shape, plugin order, and workflow naming unless the user explicitly wants a migration.Publish. For scoped public packages, use
npm publish --access public. If the repo uses a local token helper, ensure.envcontainsNPM_TOKEN=...first. If the repo usessemantic-release, ensure the workflow hasGITHUB_TOKENand anNPM_TOKENsecret available. In GitHub Actions, prefer setting bothNPM_TOKENandNODE_AUTH_TOKENto the same npm secret for npm auth checks and release steps, since npm CLI auth in CI often resolves throughNODE_AUTH_TOKENwhile@semantic-release/npmexpectsNPM_TOKEN.Troubleshoot failures by category. For package-content issues, revisit
main,exports, andfiles. For 403 errors, separate "wrong credentials" from "org requires 2FA or bypass-enabled token." For npmE401 Unauthorizedduringnpm whoamior@semantic-release/npmverify, confirm the workflow environment secret name matches the jobenvironment, confirm the secret contains the raw token only, and confirm the workflow exposes the token in the variable name the active tool actually reads. For local permission or shell issues, inspect the execution environment before changing npm config. For automated releases that do not trigger, inspect branch filters, workflow permissions, and commit message format. For GitHub Actions output-dependent steps, avoid inline shell strings that embed JavaScript template literals with backticks. Prefer shell-safeecho >> "$GITHUB_OUTPUT"or heredoc patterns so downstreamif:checks receive the expected outputs. If@semantic-release/githubthrows a secondary failure while reporting an npm auth error, makerepositoryUrlexplicit and consider disabling fail comments so the real npm problem remains visible. Forsemantic-releasetrying to publish1.0.0for an already-published package, bootstrap the repo with the existing published version tag before rerunning release automation.
Quick Checks
- Entry file exists at the path named by
mainorexports filesincludes the paths that should shippublishConfig.accessis"public"for public scoped packages.envis ignored by gitnpm pack --dry-runoutput looks correct- Active npm account or token has permission to publish under the target scope
References
Read references/publish-checklist.md for a concise pre-publish checklist and common failure modes. Read references/semantic-release.md when the repo should publish automatically from GitHub Actions.
Scripts
Use scripts/publish-with-local-token.cjs as a reusable template when a repo needs to publish with NPM_TOKEN stored in a root .env on Windows, macOS, or Linux.