Publishing a package

npm · Practical · 15 min

Shipping a library or internal package requires a clean, intentional tarball.

Before publishing, decide what goes in the tarball. Use the files allow-list in package.json (e.g. ["dist"]) rather than relying on .npmignore; package.json, README and LICENSE are always included. Preview with npm pack --dry-run, which lists every file and the size. Leaked .env files and test fixtures are common mistakes.

Required metadata: a unique name (scoped names like @you/pkg avoid collisions), version, and ideally description, license, repository, engines, plus entry points (exports, covered later).

Versioning: npm version patch|minor|major bumps version, commits and tags in Git (v1.2.4), running preversion/version/postversion scripts. Use npm version prerelease --preid=beta for betas.

Publishing:

  • npm publish uploads to the registry and moves the latest dist-tag. Scoped packages default to restricted (private) access; pass --access public the first time you publish an open-source one.
  • Publish prereleases with --tag next so they do not become latest.
  • prepublishOnly is the place to run build and tests.
  • Accounts need 2FA; automation should use trusted publishing from CI rather than long-lived tokens (later lesson).

Mistakes: npm deprecate pkg@1.2.3 "reason" warns users; npm unpublish is only freely allowed within 72 hours (and when nothing depends on the version) and is discouraged, and a version number can never be reused.

Example

# package.json (excerpt):
#   "name": "@ann/slugify", "version": "1.0.0",
#   "files": ["dist"], "license": "MIT",
#   "scripts": { "build": "tsc", "prepublishOnly": "npm run build && npm test" }

npm pack --dry-run
# npm notice package: @ann/slugify@1.0.0
# npm notice 1.1kB LICENSE
# npm notice 642B  README.md
# npm notice 2.3kB dist/index.js
# npm notice 812B  package.json
# npm notice total files: 4

npm version minor               # 1.0.0 -> 1.1.0, git commit + tag v1.1.0
npm publish --access public     # first publish of a public scoped package
git push --follow-tags

npm version prerelease --preid=beta   # 1.1.1-beta.0
npm publish --tag next                # latest stays at 1.1.0

Remember

  • Use files and check npm pack --dry-run before publishing
  • npm version bumps, commits and tags
  • Publish prereleases under a non-latest dist-tag
  • Versions can never be reused; deprecate instead of unpublishing

Watch out for

  • Publishing a beta without --tag, making it the version everyone installs.

Check yourself

  1. Why publish `2.0.0-beta.0` with `--tag next`?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.npmjs.com/cli/v11/commands/npm-publish