Publishing npm Packages
Publishing to npm means packaging your code with a correct package.json, versioning it with semver, and running npm publish so anyone can install it with npm install — turning your project into a reusable, shareable package.
Learn Publishing npm Packages in our free Node.js course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…
Part of the free Node.js course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
In this lesson you'll learn the package.json fields that matter (name, version, main, exports, files), how semver decides each version bump, how to log in and publish, what scoped packages and .npmignore do, and why you often publish a built dist folder.
What You'll Learn in This Lesson
1️⃣ The package.json Fields That Matter
Your package.json is the manifest npm reads. The critical fields: name (unique on npm), version (semver), main (the entry file loaded when someone imports you), exports (a modern, more precise entry map), and files (an allowlist of what to publish). The runnable example assembles one.
2️⃣ Names & semver Validation
npm is strict about two fields. The name must be lowercase and URL-safe, and the version must follow semver : MAJOR.MINOR.PATCH . Bump patch for fixes, minor for new compatible features, major for breaking changes. The validator below flags a bad name and a malformed version.
3️⃣ Logging In & Publishing
With a valid manifest, publishing is a few commands. npm login authenticates you, npm version patch|minor|major bumps the version (and tags git), npm publish --dry-run shows exactly what will ship, and npm publish sends it. Scoped packages are private by default, so add --access public .
Your turn. The version bumper below works once you fill in the single blank marked ___ . Follow the 👉 hint, then run it.
Mini-Challenge: A Scoped Package
No blanks — just a brief and an outline. Build a scoped package manifest that ships only the build folder and is published publicly. Build it, run it, and compare with the example output.
Common Errors (and the fix)
- ❌ "403 You do not have permission" / name taken — the unscoped name already exists. ✅ Pick a unique name or use a scope ( @you/name ).
- ❌ "You cannot publish over the previously published version" — you forgot to bump. ✅ Run npm version patch before re-publishing.
- ❌ Scoped package publish fails as private — scoped packages default to private. ✅ Add --access public .
- ❌ Source/secrets leaked into the package — no allowlist or ignore. ✅ Set a files array or .npmignore , and check with --dry-run .
- ❌ Importers get "module not found" — wrong main / exports , or you didn't publish the built file. ✅ Point them at the real entry (e.g. dist/index.js ) and include it in files .
Pro Tips
- 💡 Always --dry-run first: it prints the exact file list and size so you never publish surprises.
- 💡 Automate the build: a prepublishOnly script keeps your dist from going stale.
- 💡 Respect semver: a careless major change in a minor bump breaks everyone who trusted your version number.
📋 Quick Reference — Publishing
Task
Command / Field
Entry file
"main": "index.js"
Files to ship
"files": ["dist"]
Authenticate
npm login
Bump version
npm version patch
Preview publish
npm publish --dry-run
Publish scoped
npm publish --access public
Exclude files
.npmignore
Frequently Asked Questions
🎉 Lesson Complete!
- ✅ package.json's name , version , main / exports , and files drive how a package installs
- ✅ semver: patch for fixes, minor for features, major for breaking changes
- ✅ npm login then npm publish ships your package
- ✅ Scoped packages need --access public to be public
- ✅ files or .npmignore control what's published — verify with --dry-run
- ✅ Build to dist and publish that when your source needs compiling
- ✅ Next lesson: Debugging & Profiling Node — find bugs and bottlenecks
Practice quiz
Which command logs you in to npm before publishing?
- npm login
- npm auth
- npm signin
- npm connect
Answer: npm login. npm login creates an auth token in ~/.npmrc.
What does npm version patch do to 1.0.0?
- Makes it 2.0.0
- Makes it 1.0.1
- Makes it 1.1.0
- Leaves it unchanged
Answer: Makes it 1.0.1. A patch bump increments the last number: 1.0.0 to 1.0.1.
Which version bump is correct for a BREAKING change?
- npm version patch
- npm version minor
- npm version major
- npm version build
Answer: npm version major. Breaking changes increment the MAJOR number (e.g. 1.0.0 to 2.0.0).
How can you preview EXACTLY what will be published without shipping?
- npm publish --preview
- npm test
- npm pack --list
- npm publish --dry-run
Answer: npm publish --dry-run. npm publish --dry-run shows the file list without actually publishing.
Why do scoped packages need --access public to publish?
- They are private by default
- They are deprecated
- They cost money otherwise
- They require two-factor auth
Answer: They are private by default. Scoped (@you/name) packages default to private; --access public makes them public.
What does the "files" field in package.json control?
- Which tests run
- Which files actually get published
- The author list
- The license
Answer: Which files actually get published. The files allowlist limits what is included in the published tarball.
Which file keeps junk (like tests or .env) out of the published package?
- package-lock.json
- tsconfig.json
- .npmignore
- README.md
Answer: .npmignore. .npmignore (or the files allowlist) excludes files from publishing.
Which name is valid for an npm package?
- My Package
- GREET CLI
- Greet_CLI Pro
- greet-cli
Answer: greet-cli. npm names must be lowercase and URL-safe, like greet-cli.
What format must a package version follow?
- MAJOR.MINOR.PATCH (e.g. 1.0.0)
- A single number
- A date
- A word like stable
Answer: MAJOR.MINOR.PATCH (e.g. 1.0.0). Versions must be semver: three dot-separated numbers.
What does the "main" field in package.json specify?
- The author
- The entry file loaded when someone requires the package
- The test command
- The license URL
Answer: The entry file loaded when someone requires the package. main points to the file returned when someone imports/requires your package.
Continue this course
- Previous: Building CLI Tools
- Next: Debugging & Profiling