Ctrl + K
JavaScript10 min read

What Is npm?

Understand what npm is, how packages and dependencies work, how npm commands manage JavaScript projects and how package.json and package-lock.json fit into the workflow.

Published: 2026-09-02

npm is the default package manager commonly used with Node.js. It allows developers to install JavaScript packages, manage project dependencies, run scripts and publish reusable packages to the npm registry.

Modern JavaScript applications often depend on dozens or even hundreds of external packages. npm provides the tools needed to download those packages, keep track of their versions and reproduce the same dependency setup across different development environments.

What Does npm Stand For?

npm is commonly expanded as Node Package Manager. The name reflects its original role as a package manager for the Node.js ecosystem, although npm is now also an important part of the broader JavaScript development ecosystem.

What Does npm Do?

  • Install JavaScript packages.
  • Manage project dependencies.
  • Track package versions.
  • Run project scripts.
  • Create and initialize JavaScript projects.
  • Publish packages to the npm registry.
  • Remove and update dependencies.

npm and Node.js

npm is distributed with Node.js installations in typical development environments. Node.js provides the JavaScript runtime, while npm provides package management and project automation capabilities.

TechnologyPrimary Purpose
Node.jsRuns JavaScript outside the browser
npmManages packages and project dependencies
npm RegistryStores and distributes packages

Checking the npm Version

The npm command-line interface can display its installed version. Checking the version is useful when troubleshooting projects because npm behavior can vary between major releases.

npm --version

Creating a New npm Project

A new npm project can be initialized with npm init. The command creates a package.json file containing metadata and configuration for the project.

mkdir my-app
cd my-app
npm init

For projects where the default answers are sufficient, npm init -y can generate package.json without asking the usual interactive questions.

npm init -y

What Is package.json?

The package.json file is the central metadata and dependency configuration file for many npm projects. It can contain the project name, version, scripts, dependencies, development dependencies and other package metadata.

{
  "name": "my-app",
  "version": "1.0.0",
  "scripts": {
    "start": "node index.js"
  },
  "dependencies": {
    "express": "^5.0.0"
  }
}

Installing a Package

The npm install command downloads a package and normally records it as a dependency in package.json. npm also installs the package's own dependencies when necessary.

npm install express

After installation, the package is normally placed inside the project's node_modules directory and its dependency information is recorded in the project's package files.

Installing Development Dependencies

Packages used only during development can be installed as development dependencies. Typical examples include testing frameworks, linters, formatters, TypeScript tooling and build tools.

npm install --save-dev typescript
Dependency TypeTypical Purpose
dependenciesRequired by the application
devDependenciesRequired for development and build tasks

Installing Packages Globally

npm also supports global package installation. Global packages are intended for command-line tools that developers want to use outside a specific project, although many modern workflows prefer project-local installations and npm scripts.

npm install --global package-name
⚠️ Avoid installing project dependencies globally. A package required by an application should normally be declared in the project's package.json so other developers and build systems can install the same dependency.

The node_modules Directory

The node_modules directory contains packages installed for a project. It can become large because dependencies may themselves depend on additional packages, creating a dependency tree.

my-app/
├── node_modules/
├── package.json
├── package-lock.json
└── index.js

The node_modules directory is normally not committed to Git. Instead, the project stores dependency declarations and lockfile information so the directory can be recreated when dependencies are installed.

What Is package-lock.json?

package-lock.json records the exact dependency tree resolved by npm. While package.json can specify version ranges, the lockfile records the specific versions and package relationships used by an installation.

npm install

The lockfile helps different developers and automated environments install a consistent dependency tree. It is therefore normally committed to version control for applications.

npm install vs npm ci

npm install and npm ci can both install project dependencies, but they serve different purposes. npm install can update the lockfile when dependency information changes, while npm ci is designed for clean, reproducible installations based on the existing lockfile.

CommandTypical Use
npm installDevelopment and dependency changes
npm ciCI/CD and clean reproducible installations
npm ci
💡 Use npm ci in automated builds when package-lock.json is committed and should be treated as the exact dependency definition for the installation.

Removing a Package

npm uninstall removes a package from the project and updates the relevant package metadata. This is preferable to manually deleting a package directory because npm also updates dependency declarations.

npm uninstall express

Updating Dependencies

npm provides commands for checking and updating outdated dependencies. The npm outdated command displays packages for which newer versions are available.

npm outdated

Updating dependencies should be done deliberately because a newer package version can introduce breaking changes, behavior changes or new transitive dependencies.

Semantic Versioning and npm

npm packages commonly use Semantic Versioning, or SemVer, to communicate compatibility between releases. Versions typically follow the MAJOR.MINOR.PATCH pattern.

2.4.1
│ │ │
│ │ └── Patch
│ └──── Minor
└────── Major
Version ChangeTypical Meaning
MajorPotentially breaking changes
MinorBackward-compatible features
PatchBackward-compatible fixes

Version Ranges

package.json can specify dependency version ranges instead of a single exact version. Common prefixes such as the caret and tilde allow npm to select compatible releases according to the declared range.

{
  "dependencies": {
    "package-a": "^2.4.0",
    "package-b": "~1.8.2"
  }
}

The exact versions installed by a project are resolved and recorded in package-lock.json. This separation allows package.json to express acceptable version ranges while the lockfile preserves a reproducible dependency tree.

npm Scripts

npm scripts provide a convenient way to define reusable commands in package.json. They are commonly used for development servers, builds, tests, linting, formatting and deployment tasks.

{
  "scripts": {
    "dev": "vite",
    "build": "tsc && vite build",
    "test": "vitest",
    "lint": "eslint ."
  }
}

Scripts can then be executed with npm run followed by the script name. Some standard lifecycle commands such as npm test and npm start have dedicated shorthand forms.

npm run dev
npm run build
npm run lint
npm test

npm Registry

The npm registry is a public package registry containing JavaScript packages that can be downloaded through npm. Developers can publish their own packages or install packages maintained by other developers and organizations.

Publishing an npm Package

Developers can publish reusable JavaScript packages to the npm registry. Publishing requires package metadata, an appropriate package version and authentication with an npm account.

npm login
npm publish
⚠️ Publishing is a permanent distribution action. Review package contents, package.json metadata and included files carefully before publishing, especially when a package could contain credentials or private source files.

Checking Dependency Problems

npm can inspect dependency trees and report security vulnerabilities found in installed packages. The npm audit command is commonly used as part of dependency maintenance.

npm audit

A reported vulnerability does not always mean that an application is immediately exploitable. Developers should examine the affected dependency, vulnerability details, available fixes and how the package is used by the application.

npm Dependency Tree

Modern applications often use transitive dependencies. A project may directly install one package while that package depends on several other packages. npm resolves these relationships and creates the resulting dependency tree.

npm ls

The dependency tree is important when debugging duplicate packages, version conflicts and security issues because a problematic package may not be listed directly in package.json.

Cleaning and Reinstalling Dependencies

When dependency installation becomes inconsistent, developers sometimes remove node_modules and reinstall packages from the project's package files. This can resolve problems caused by corrupted or outdated local dependency state.

rm -rf node_modules
npm ci
⚠️ The rm -rf command is destructive. On Windows or when working with important files, use an appropriate platform-specific method and verify that the target directory is correct before deleting it.

npm Workspaces

npm supports workspaces for managing multiple related packages from a single repository. This is useful for monorepos where an application and several internal packages are developed together.

{
  "workspaces": [
    "packages/*",
    "apps/*"
  ]
}

Common npm Mistakes

  • Committing node_modules to Git.
  • Installing application dependencies globally.
  • Ignoring package-lock.json in application projects.
  • Updating many dependencies without reviewing breaking changes.
  • Running npm commands from the wrong project directory.
  • Ignoring dependency security warnings.
  • Manually editing dependency state inside node_modules.

Best Practices

  • Keep package.json accurate and up to date.
  • Commit package-lock.json for applications.
  • Use npm ci for reproducible CI/CD installations.
  • Keep project dependencies local whenever possible.
  • Review dependency updates before applying them.
  • Run security audits regularly.
  • Avoid committing node_modules.
  • Use npm scripts for repeatable project commands.
  • Remove unused dependencies.
💡 Treat package.json and package-lock.json as part of the project's source of truth for dependencies. Keeping them consistent makes local development, code review and automated builds much more predictable.
⚠️ Do not blindly update every dependency to the newest available version. Major releases can introduce breaking changes, and even minor updates can affect behavior through transitive dependencies.

Frequently Asked Questions

What is npm used for?

npm is used to install and manage JavaScript packages, maintain project dependencies, run scripts, inspect dependency trees, audit packages and publish reusable packages.

Does npm come with Node.js?

Typical Node.js installations include npm, allowing developers to use the npm command-line interface immediately after installing Node.js.

What is the difference between npm and Node.js?

Node.js is a JavaScript runtime that executes JavaScript outside the browser, while npm is a package manager used to install dependencies and manage JavaScript projects.

Should package-lock.json be committed?

For applications, package-lock.json should normally be committed because it records the resolved dependency tree and helps developers and CI systems reproduce installations consistently.

What is the difference between npm install and npm ci?

npm install is commonly used during development and can update the lockfile, while npm ci is intended for clean installations based on the existing package-lock.json and is commonly used in CI/CD environments.

Helpful npm Tools

A Package.json Formatter formats package metadata into a consistent structure, a Package.json Validator checks package files for structural problems, an npm Dependency Checker helps inspect project dependencies, an npm Version Calculator assists with determining version changes, and a Package-lock Inspector helps examine dependency information stored in package-lock.json.

Conclusion

npm is a fundamental part of the Node.js and JavaScript ecosystem. It provides a complete workflow for installing packages, managing dependencies, running project scripts and distributing reusable software. Understanding package.json, package-lock.json, semantic versioning, npm scripts and dependency management helps developers build projects that are easier to reproduce, maintain and deploy. By keeping dependencies organized, using lockfiles appropriately and reviewing updates carefully, teams can make npm a reliable part of their development workflow.

Found an issue?

Found an error, outdated information, or something missing from this article? Let me know through the Contact page.

Your feedback helps improve our articles and keep them accurate and useful.