Publishing a Package
Publishing a package makes it available on the npm registry so that anyone (or members of your organisation) can install it with npm install. The process involves three steps: preparing package.json with the right metadata, bumping the version, and running npm publish. Each step has guardrails that help you ship clean, predictable releases.
Key package.json fields for publishing
Section titled “Key package.json fields for publishing”Three fields control what consumers receive and how they can use your package:
{ "name": "my-util-lib", "version": "1.0.0", "description": "A small utility library",
"files": ["dist", "README.md"],
"bin": { "my-util": "./dist/cli.js" },
"exports": { ".": { "import": "./dist/index.mjs", "require": "./dist/index.cjs" }, "./helpers": { "import": "./dist/helpers.mjs", "require": "./dist/helpers.cjs" } }}files— an allowlist of paths included in the published tarball. Everything else (source files, test fixtures, config) is excluded. If omitted, npm applies a default set of exclusions.bin— maps a CLI command name to an entry-point script. npm creates a symlink in.bin/so the command is available in the PATH when the package is installed.exports— declares the public API surface. Any path not listed here is inaccessible to consumers.
Bumping the version with npm version
Section titled “Bumping the version with npm version”npm follows semantic versioning (semver). Use npm version to bump and tag in one step:
# Patch bump: 1.0.0 → 1.0.1 (bug fixes)npm version patch
# Minor bump: 1.0.1 → 1.1.0 (backwards-compatible new features)npm version minor
# Major bump: 1.1.0 → 2.0.0 (breaking changes)npm version majorEach command updates the "version" field in package.json, commits the change, and creates a signed git tag (e.g. v1.0.1). Push the tag with git push --follow-tags.
Publishing with npm publish
Section titled “Publishing with npm publish”# Publish a public (unscoped) packagenpm publish
# Publish a scoped package as public (scoped packages default to restricted)npm publish --access publicnpm reads package.json to determine the registry target (defaults to https://registry.npmjs.org). You must be authenticated (npm login) before publishing.
Scoped packages
Section titled “Scoped packages”A scoped package uses the @scope/name format and is typically used for organisation namespacing or to group related packages:
{ "name": "@myorg/my-util-lib", "version": "1.0.0"}Scoped packages are private by default on the npm registry. To publish them publicly, always pass --access public:
npm publish --access publicPrivate scoped packages require a paid npm account or a private registry.
Testing before publish with npm pack
Section titled “Testing before publish with npm pack”npm pack bundles your package into a .tgz tarball exactly as npm would if you ran npm publish — but it stays local. This lets you inspect the final artifact before shipping it.
# Create a local tarball (e.g. myorg-my-util-lib-1.0.0.tgz)npm pack
# Inspect its contents without extractingtar -tzf myorg-my-util-lib-1.0.0.tgz
# Install it locally in another project to smoke-testnpm install ../my-util-lib/myorg-my-util-lib-1.0.0.tgz