Npm Publishing
Publishing packages to the npm registry with proper configuration, access control, and release automation
You are an expert in publishing packages to the npm registry, including configuration, access scoping, automation, and lifecycle management. ## Key Points - **name**: Must be unique on the registry. Scoped packages use `@scope/package-name`. - **version**: Must follow SemVer and be incremented before each publish. - **main / module / exports**: Entry points consumers will resolve. - **files**: Allowlist of files to include in the tarball (preferred over `.npmignore`). - **publishConfig**: Override registry, access level, or tag at publish time. - **repository / license / description**: Metadata displayed on npmjs.com. - **engines**: Declare minimum Node.js version requirements. - **type**: Set to `"module"` for ESM-first packages. - **public**: Anyone can install the package. Default for unscoped packages. - **restricted**: Only users/teams with explicit access can install. Default for scoped packages on paid orgs. - `latest` (default): What users get with `npm install <pkg>`. - `next`, `beta`, `canary`, `rc`: Used for pre-release channels. ## Quick Example ```bash npm publish --tag beta npm dist-tag add @myorg/utils@3.0.0-beta.1 beta npm dist-tag ls @myorg/utils ``` ```bash npm pack --dry-run # Or inspect the actual tarball npm pack tar -tzf myorg-utils-2.1.0.tgz ```
skilldb get package-management-skills/Npm PublishingFull skill: 234 linesnpm Publishing — Package Management
You are an expert in publishing packages to the npm registry, including configuration, access scoping, automation, and lifecycle management.
Core Philosophy
Overview
Publishing to npm involves preparing a package with correct metadata, choosing access levels (public or restricted), managing authentication tokens, and automating the release pipeline. A well-configured publish workflow prevents broken releases, leaked files, and version conflicts.
Core Concepts
package.json Fields That Matter for Publishing
- name: Must be unique on the registry. Scoped packages use
@scope/package-name. - version: Must follow SemVer and be incremented before each publish.
- main / module / exports: Entry points consumers will resolve.
- files: Allowlist of files to include in the tarball (preferred over
.npmignore). - publishConfig: Override registry, access level, or tag at publish time.
- repository / license / description: Metadata displayed on npmjs.com.
- engines: Declare minimum Node.js version requirements.
- type: Set to
"module"for ESM-first packages.
The exports Field (Package Entry Points)
The exports field provides explicit entry point mapping and encapsulation:
{
"name": "@myorg/utils",
"version": "2.1.0",
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs",
"types": "./dist/index.d.ts"
},
"./helpers": {
"import": "./dist/helpers.mjs",
"require": "./dist/helpers.cjs",
"types": "./dist/helpers.d.ts"
}
},
"files": ["dist"],
"publishConfig": {
"access": "public"
}
}
npm Access Levels
- public: Anyone can install the package. Default for unscoped packages.
- restricted: Only users/teams with explicit access can install. Default for scoped packages on paid orgs.
Dist Tags
latest(default): What users get withnpm install <pkg>.next,beta,canary,rc: Used for pre-release channels.
npm publish --tag beta
npm dist-tag add @myorg/utils@3.0.0-beta.1 beta
npm dist-tag ls @myorg/utils
Implementation Patterns
Basic Publish Workflow
# Authenticate (one-time or CI token)
npm login
# or set NPM_TOKEN in CI
# Verify what will be published
npm pack --dry-run
# Bump version (updates package.json and creates git tag)
npm version patch # 1.0.0 -> 1.0.1
npm version minor # 1.0.0 -> 1.1.0
npm version major # 1.0.0 -> 2.0.0
# Publish
npm publish
# For scoped packages that should be public
npm publish --access public
Controlling Published Files
Use the files field as an allowlist (preferred approach):
{
"files": [
"dist",
"README.md",
"LICENSE"
]
}
Always verify the tarball contents before publishing:
npm pack --dry-run
# Or inspect the actual tarball
npm pack
tar -tzf myorg-utils-2.1.0.tgz
Prepublish Scripts
{
"scripts": {
"prepublishOnly": "npm run build && npm test",
"preversion": "npm test",
"postversion": "git push && git push --tags"
}
}
CI-Based Publishing with GitHub Actions
name: Publish
on:
push:
tags:
- 'v*'
jobs:
publish:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write # Required for npm provenance
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
registry-url: https://registry.npmjs.org
- run: npm ci
- run: npm test
- run: npm publish --provenance --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
npm Provenance
npm provenance links published packages to their source repo and build, increasing supply chain trust:
npm publish --provenance
Requires: GitHub Actions (or GitLab CI) with id-token: write permission and the package linked to a public repo.
Automating Releases with Changesets
npm install -D @changesets/cli
npx changeset init
Workflow:
- Contributors run
npx changesetand describe their changes. - CI runs
npx changeset versionto bump versions and update changelogs. - CI runs
npx changeset publishto publish updated packages.
{
"scripts": {
"release": "changeset publish"
}
}
Two-Factor Authentication
Enable 2FA on your npm account for publish operations:
npm profile enable-2fa auth-and-writes
For CI, use granular access tokens with limited permissions and IP allowlists.
Best Practices
- Always use the
filesallowlist rather than.npmignoreto control what gets published. - Run
npm pack --dry-runbefore every publish to verify tarball contents. - Use
prepublishOnlyto build and test automatically before publish. - Enable npm provenance for supply chain transparency.
- Use automation tokens with minimal scope for CI publishing.
- Publish pre-releases to a dist tag (
--tag beta) so they never becomelatest. - Include
typesin theexportsfield for TypeScript consumers. - Set
"sideEffects": falseif the package is tree-shakeable. - Use
npm deprecateinstead of unpublishing when retiring a version. - Use
npm owner lsto audit who has publish access.
Common Pitfalls
- Publishing without building: Forgetting to run the build step, resulting in missing dist files. Use
prepublishOnlyto guard against this. - Leaking secrets or source: Not using the
filesfield, accidentally including.env, config files, or test fixtures in the tarball. - Version conflicts: Running
npm publishwithout incrementing the version, causing a 403 error. - Scoped package access: Scoped packages default to restricted. First publish of a public scoped package requires
--access public. - Broken entry points: Mismatched
exports/main/modulepaths that point to files not included in the tarball. - Unpublishing regret: npm only allows unpublishing within 72 hours. After that, versions are permanent. Use
npm deprecateinstead. - Missing
typescondition: TypeScript users get no type resolution if thetypescondition is missing fromexports. - Forgetting
--tagfor pre-releases: Publishing1.0.0-beta.1without--tag betamakes it thelatestversion that all users will install by default.
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add package-management-skills
Related Skills
Bundling Libraries
Bundling JavaScript/TypeScript libraries for distribution using tsup, unbuild, and Rollup
Dependency Audit
Security auditing npm dependencies for vulnerabilities, license compliance, and supply chain risks
Lockfile Management
Lock file strategies for deterministic installs across npm, pnpm, and Yarn
Pnpm
pnpm workspace management for monorepos with content-addressable storage and strict dependency isolation
Private Registries
Setting up and using private npm registries with Verdaccio, GitHub Packages, and GitLab Package Registry
Semantic Versioning
Semantic versioning (SemVer) conventions, version ranges, and strategies for managing breaking changes