If you’ve spent any time working with JavaScript, you’ve most likely come across npm—whether installing packages like Express, Lodash, or React, or running commands like npm init. While using npm is second nature for many JavaScript developers, some have never explored how those packages are created, structured, and shared with the rest of the world. Behind each command lies a powerful system for building, managing, and distributing JavaScript code at scale.

This article will guide you through the basics of npm, explain how it functions behind the scenes, and demonstrate step-by-step how to create and publish your own npm package to the official npm registry. Whether you’re a beginner just starting with JavaScript or a seasoned developer who has used npm but never published a package, this guide will help you confidently navigate the entire process, from setup to sharing your code with the global developer community.

Table of Contents

What is npm?

npm, which stands for Node Package Manager, is a command-line tool for installing and managing JavaScript packages. It is an ecosystem that powers modern JavaScript development (Node.js, frontend tools, frameworks, and so on). Developers use npm to share and borrow packages, and many organizations use npm to manage private development.

Essentially, npm is to JavaScript what pip is to Python or Maven to Java. It enables developers to reuse code written by others (most of the time to fulfil a function in their project), manage dependencies, and share their own code with the world.

You can use npm to:

  • Get and utilize code packages in your applications, either as-is or with custom modifications.

  • Download and run standalone tools instantly.

  • Execute packages directly from the registry without installing them using npx.

  • Share your own code with developers around the world through the npm registry.

  • Limit access to specific packages so only approved developers can use them.

  • Create organizations to manage code, teams, and packages in one place.

  • Collaborate as virtual teams using shared organizational accounts.

  • Handle different versions of packages and their dependencies with ease.

  • Keep your applications up to date by syncing with the latest package updates.

  • Explore different packages that offer various solutions to the same problem.

  • Connect with developers working on similar challenges and projects.

Components of npm

npm consists of three core components:

  • The command line interface (CLI)

  • The registry

  • The website

The Command Line Interface

There are different npm commands you can run on your terminal. For example, npm init can be used to initialize a Node project, npm install can be used to install a package. It also allows you to do things like:

  • Publish packages (npm publish)

  • Update packages (npm update)

  • Manage versioning (npm version)

  • Run scripts (npm run build, npm test, and so on)

Think of it as your control panel.

The Registry

You can find the huge public database at https://registry.npmjs.org, where packages are stored and shared. It also contains all the meta-information surrounding the package.

Example, when you run:

npm install express

npm fetches the Express package from the registry.

The npm registry enables collaboration by allowing developers to:

  • Publish their own packages

  • Install packages created by others

  • Discover new tools and libraries

Its collaboration features include:

  • Open-source packages: The code is publicly visible (usually hosted on GitHub).

  • Versioning: Multiple versions of the same package let users safely adopt updates.

  • Scoped packages: Namespaces allow teams and organizations to manage ownership.

  • Issues & pull requests: Most npm packages link to GitHub, allowing developers too contribute fixes and enhancements.

  • Organisations: Teams can manage access to shared private or public packages.

The Website

At https://www.npmjs.com, this is where you can:

  • Browse packages.

  • Read documentation.

  • View download stats and dependencies.

  • Create and manage your account, organization, and package access.

What is the Package.json File?

A very important component of any npm tool that you’ll come across as a JavaScript developer installing an npm package, is the package.json file. It is a metadata file that lives at the root of every npm or Node project. It tells npm (and other tools) everything it needs to know about your project, like:

  • What the project is called.

  • What it depends on

  • How to run it

  • How to version it

  • and how to publish it

You can think of it like the blueprint of your JavaScript project. Without it, npm doesn't know how to work with your code.

You can create a package.json file by typing the command npm init in your terminal and filling in the prompts provided. Alternatively, you can create a file named package.json and manually populate it with JSON content.

Key Fields in an npm package.json File

The following is a list of commonly used fields and how they interact with npm:

  1. name and version

     "name": "my-awesome-package",
     "version": "1.0.0"
    
    • This is required for publishing.

    • name must be unique (if publishing to the public npm registry).

    • version follows semantic versioning (semver) (for example, major.minor.patch).

  2. description, keywords, author, and license

     "description": "A utility to convert markdown to HTML",
     "keywords": ["markdown", "html", "converter"],
     "author": "Ikegah Oliver",
     "license": "MIT"
    
    • Helps npm users discover your package

    • Show up on npmjs.com.

    • Sets collaboratory license

  3. scripts

     "scripts": {
       "start": "node index.js",
       "test": "jest",
       "build": "tsc"
     }
    
    • Defines custom commands.

    • Run with npm run test, npm run build, and so on.

    • Automates build, test, lint, deploy processes.

  4. main and exports

     "main": "dist/index.js",
     "exports": {
       ".": "./dist/index.js"
     }
    
    • main: Entry point for require() or import.

    • exports: Controls exactly what parts of your package are exposed (especially useful for modern ESM and package security).

  5. dependencies and devDependencies

     "dependencies": {
       "express": "^4.18.2"
     },
     "devDependencies": {
       "eslint": "^8.0.0",
       "jest": "^29.0.0"
     }
    
    • dependencies : Core packages your project needs to run in production (for example, express).

    • devDependencies : Packages used only during development, like testing or build tools (for example, jest).

  6. engines

     "engines": {
       "node": ">=14.0.0"
     }
    
    • Specifies Node.js version your package supports.

    • Helps warn users before they install with an unsupported version.

  7. private

     "private":"true"
    
    • Prevents accidental publishing to the public npm registry.

    • Used for monorepos and internal-only projects.

  8. files (optional)

     "files":["/dist", "README.md"]
    
    • Controls what files get included when you run npm publish.

    • Reduces package size, omits build artifacts or test files.

A minimal npm package.json file looks like this:

{
  "name": "@oliver/markdown-to-html",
  "version": "1.0.0",
  "description": "Converts markdown to HTML with styles",
  "main": "dist/index.js",
  "scripts": {
    "build": "tsc",
    "test": "jest"
  },
  "keywords": ["markdown", "html", "converter"],
  "author": "Ikegah Oliver",
  "license": "MIT",
  "dependencies": {
    "marked": "^5.0.0"
  },
  "devDependencies": {
    "jest": "^29.0.0"
  },
  "engines": {
    "node": ">=14.0.0"
  },
  "files": ["dist/", "README.md"]
}

The package.json file plays a central role in every npm workflow. It defines your project's identity, lists its dependencies, specifies useful scripts, and outlines how the package should behave when published. Without it, npm can't properly install packages, run commands, or publish your code to the registry.

How npm Works

When you type npm install in your terminal, npm initiates a behind-the-scenes process to install the necessary packages for your project. Depending on how you run the command, the process varies slightly as follows:

Method 1 - package.json Already Has Dependencies

If your package.json lists packages under dependencies or devDependencies, npm will:

  1. Read those entries: It looks at the names and version ranges of each dependency.

  2. Contact the registry: npm queries https://registry.npmjs.org to fetch metadata about each required package.

  3. Download the correct versions: It selects versions that match your version rules (such as ^4.17.0) and downloads the .tgz files.

  4. Unpack and install: It places the packages into the node_modules directory and caches them.

  5. Update package-lock.json: It logs the exact versions and dependency tree in this file to ensure consistent installs later.

Method 2 - You Run npm install <package-name> Without Existing Dependencies

If your package.json doesn't have any dependencies yet and you run something like this in your terminal:

npm install express

Then npm will run:

  1. Resolve the package version: It fetches the latest version of Express (unless you specify a version manually).

  2. Download and install: The tarball is downloaded and placed in the node_modules/ folder that is automatically generated. A tarball is the zipped-up version of the package (express in this case), containing the package’s JavaScript files, a package.json, a README, and anything else the author included for distribution that npm downloads and extracts onto your machine.

  3. Add to package.json: npm automatically adds the package to your dependencies list like this:

"dependencies": {
  "express": "^4.18.2"
}
  1. Create a package-lock.json (if it doesn't exist): It writes all the version info to lock things down for future installs.

Note: If you run npm install --save-dev jestIt’ll add the package under devDependencies instead.

How to Publish an npm Library

To follow through with this guide section, you will need to have the following prerequisites:

  • Stable network connection

  • A code editor with a terminal (like VSCode)

  • Basic knowledge of JavaScript and Node

  • A basic understanding of the Markdown Markup language (for README documentation)

Now, let’s dive into publishing an npm library. Assuming you just built and tested a fantastic JavaScript tool that you would like to share with the world, and allow people to use it in their projects and applications, the steps below will guide you from having the tool on your local machine to making it publicly available as an npm package for anyone to install and enjoy:

Step 1: Create a free npm account

Before publishing, you will need an npm account.

  • Go to https://www.npmjs.com/signup.

  • Fill in the form with your username, email, and password.

  • Confirm your email address by clicking the link in the verification email.

Step 2: Log in from the Command Line

Once you’ve created your account, you need to log in through your terminal. Run:

npm login

npm will prompt you for your username, password, and email address. If everything is correct, npm will generate an authentication token and store it locally, so you don’t have to log in every time.

Step 3: Create a package.json file

If your project doesn't already have a package.json file, create one by typing this command in your terminal:

npm init

You will be prompted to fill in the following information:

  • name: Must be unique if it’s public.

  • version: Start with 1.0.0 (it represents the first version of your project; subsequently, you will change it accordingly after each update push)

  • description: One-line summary of your package.

  • entry point: Entry file of your project, usually index.js or dist/index.js.

  • keywords: Help others discover your package.

  • author: Your name or GitHub handle.

  • license: Use MIT, ISC, or another open-source license.

When you’re done, npm will generate a package.json like this:

{
  "name": "my-awesome-package",
  "version": "1.0.0",
  "description": "A demo package for npm publishing",
  "main": "index.js",
  "keywords": ["demo", "npm", "tutorial"],
  "author": "Your Name",
  "license": "MIT"
}

Step 4: Add a README.md

Explain what your package does and how to use it in a README.md file. The README appears on your package page on npmjs.com. Example content:

# my-awesome-package

A simple package that says hello.

## Usage

```js
const greet = require('my-awesome-package');
console.log(greet('Oliver'));
// Output: Hello, Oliver!

Step 5:Add an .npmignore file

This will exclude folders like node_modules, dist, or .env, and any other file or folder within the package you don’t wish to publish. Example content:

node_modules
.env
dist

Step 6: Check if the package name you chose is available

Before publishing, check if the package name you chose is not already taken. To check, run this command on your terminal:

npm search my-awesome-package

Or enter the URL https://www.npmjs.com/package/my-awesome-package in your browser (replace my-awesome-package with the name you chose). If no package page shows up, the name is not taken.

If the package name has been taken, change it in your package.json and any documentation (README.md), the name is reflected, or publish it under a scope. A scope is like a namespace tied to your npm username or organization. It ensures your package name is unique, even if the base name is common. For example, if my-awesome-package is taken, you can publish under a scope by setting the name section in its package.json like this:

{
  "name": "@yourname/my-awesome-package"
}

Step 6: Publish your package

You are now ready to publish. Run:

npm publish

If you used a scoped name, when publishing, you must make it public:

npm publish --access public

If everything is valid, npm will publish your package and give you a URL like:

https://www.npmjs.com/package/my-awesome-package

How to Verify and Install Your Package

Visit your project page on npm to see it live. For example: https://www.npmjs.com/package/my-awesome-package, or search your project name on the npm website search bar.

Now, try installing it in a node project:

npm install my-awesome-package

Test out its features and functionalities, depending on what it is built to do.

How to Update Your Package

If you make changes or update features in your package, you can publish the update.

After applying your changes, you can update the version in your package.json. Using semantic versioning, you can update it as follows:

  • Patch update: 1.0.0 → 1.0.1

  • Minor update: 1.0.0 → 1.1.0

  • Major update: 1.0.0 → 2.0.0

Or you can use the CLI:

npm version <update_type>

Replace <update_type> with your new semantic version.

Now run:

npm publish

Notes and Best Practices

Although publishing to npm is straightforward, you still need to follow best practices to maintain a clean, secure, and user-friendly package.

  • Exclude Sensitive Files: Never include .env, credentials, or secrets. Use .npmignore or the "files" field in package.json to control what gets published.

  • Test Before Publishing: Run npm pack to preview the package and install it locally in another project to ensure everything works.

  • Unpublish Carefully: You can unpublish within 72 hours using npm unpublish --force, but avoid doing this frequently to prevent breaking other projects that rely on your package.

  • Always Bump the Version: npm won’t let you overwrite a version, so use semantic versioning (npm version patch|minor|major) before publishing updates.

  • Add Essentials: Include a clear README.md file, a license, and relevant keywords to make your package discoverable and easy to use.

Beyond the Basics

Now that you've got the hang of the basics, you can put your npm skills to work and level up as a developer. Here are some simple, practical steps you can take:

Get Involved in Open Source

One of the best ways to gain real-world experience is by contributing to existing projects on npm. Check out their repositories on GitHub and GitLab and see how you can contribute to them. This teaches you how to collaborate, handle code reviews, and manage versions. A great way to start is by looking for projects on GitHub with a "good first issue" label.

Maintain Your Own Package

Publishing is just the first step. To truly master the process, keep your package up to date. This involves fixing bugs, listening to user feedback, and adding new features. You will quickly learn about versioning, ensuring your package remains compatible with older projects, and effectively manage dependencies.

Dig into Advanced Features

Explore advanced npm topics like semantic versioning, using private packages, creating scoped packages, and automating your releases with CI/CD pipelines. These are essential skills for any professional developer.

Taking these steps will help you transition from merely understanding npm to confidently utilizing it in real-world scenarios.

Conclusion

Congratulations! You have now learned the essentials of npm from the package.json file to publishing and maintaining a JavaScript package with the npm library. With this knowledge, you can share your JavaScript tools with the world, collaborate with other developers, and contribute to the growing ecosystem of open-source libraries.

By following best practices, testing locally, and learning from standard errors, you can confidently create packages that are clean, secure, and useful for other developers. Whether you’re building a small utility or a full-fledged framework, publishing on npm gives your ideas visibility and helps you contribute to the wider JavaScript community.

If you’d like to get hands-on experience collaborating on a real package, I published an npm project called route-pilot, a powerful CLI tool for testing and analyzing Express.js routes in your Node.js applications. I’m actively seeking contributors who want to enhance the code, add new features, or refine the documentation. It’s a simple way to practice working with npm in a collaborative setting while learning more about open-source development. Head over to the GitHub repo and join in. We’d love to have you on board!