Node.js: npm Package Manager
Last updated: 2026-08-26
Alice had just taken on a new project that required adding the Luxon date-handling library and the Express HTTP framework, as well as configuring the Jest testing tool. At first, she downloaded the JavaScript files one by one from their official websites and manually copied them into her project, but she constantly ran into version conflicts, and upgrading was a nightmare. That was until a colleague introduced her to npm—a single command to install dependencies, with versions recorded in package.json and locked to exact versions via the lock file. Since then, the team has never again encountered the “it works on my machine” issue.
You'll learn:
- Use
npm init,npm install, andnpm uninstallto manage project dependencies - Distinguish between dependencies and devDependencies and their respective use cases
- Understand the purpose of
package-lock.jsonand the commit strategy - Understand the SemVer semantic versioning rules (^, ~, >=, etc.)
- Boost Development Efficiency with npm Scripts and npx
1. npm init — Initialize a project
(1) Interactive Initialization
Running npm init will prompt you to enter project information step by step, ultimately generating package.json.
▶ Example: Creating a package.json file interactively
mkdir my-project && cd my-project
npm init
package name: (my-project)
version: (1.0.0)
description: A sample project
entry point: (index.js)
test command: jest
git repository:
keywords:
author: Alice
license: (ISC)
(2) Quick Initialization
Use -y to skip all prompts and generate the default package.json.
▶ Example: Skip the prompts to generate quickly
npm init -y
Wrote to /home/alice/my-project/package.json
Generated package.json default content:
{
"name": "my-project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"license": "ISC"
}
2. npm install / uninstall — Installing and Uninstalling Dependencies
(1) Install dependencies
npm install <package> Download the package to node_modules and write it to package.json.
▶ Example: Installing Production Dependencies
npm install express
(2) Install development dependencies
--save-dev (abbreviated as -D) logs packages to devDependencies and is intended for use in development environments only.
▶ Example: Installing Development Dependencies
npm install jest --save-dev
(3) Uninstall dependencies
npm uninstall Delete both the files in node_modules and the records in package.json.
▶ Example: Uninstalling a dependency
npm uninstall express
(4) Install all dependencies
After cloning someone else's project, run npm install to restore all dependencies using package.json and package-lock.json.
▶ Example: Restoring Dependencies
npm install
| Command | Function | Fields to Fill |
|---|---|---|
npm install <pkg> |
Install production dependencies | dependencies |
npm install <pkg> --save-dev |
Install development dependencies | devDependencies |
npm install <pkg> -g |
Global installation | Do not write to package.json |
npm uninstall <pkg> |
Uninstall Dependencies | Remove Corresponding Fields |
npm install |
Restore all dependencies according to the list | — |
3. dependencies vs. devDependencies
(1) Dependency Classification
dependencies Lists the packages required for the production environment; devDependencies lists the packages used only during the development phase.
▶ Example: Dependency sections in package.json
{
"dependencies": {
"express": "^4.18.2",
"luxon": "^3.4.4"
},
"devDependencies": {
"jest": "^29.7.0",
"eslint": "^8.56.0"
}
}
(2) Skip development dependencies during production installation
Use --production or set NODE_ENV=production to skip installing devDependencies and reduce the deployment size.
▶ Example: Installation in a Production Environment
npm install --production
| Comparison Item | dependencies | devDependencies |
|---|---|---|
| Purpose | Required for production operations | For development/testing only |
| Installation Command | npm install <pkg> |
npm install <pkg> -D |
| Production Installation | Always Install | Skip when --production |
| Typical packages | express, luxon, axios | jest, eslint, nodemon |
| Deployment Requirements | Must Include | Optional |
4. The Purpose of package-lock.json
(1) Lock the exact version
package-lock.json Record the exact version and integrity hash of each dependency to ensure that installation results are consistent across all environments.
(2) Improve installation speed
The lock file contains the complete dependency tree, allowing npm to skip version resolution and download the packages directly.
▶ Example: lock file snippet
{
"node_modules/luxon": {
"version": "3.4.4",
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.4.4.tgz",
"integrity": "sha512-zaBViHBuQffgP8h...',
"requires": {}
}
}
| Property | Function |
|---|---|
| version | Exact version number |
| resolved | Package download link |
| integrity | SHA-512 hash, integrity check |
| requires | List of this package's subdependencies |
5. Semantic Versioning (SemVer)
(1) Version Number Format
The SemVer format is MAJOR.MINOR.PATCH, with each component having a specific meaning.
(2) Version Range Symbols
Use symbols in package.json to constrain the acceptable version range.
| Symbol | Meaning | ^1.2.3 Allowable Range |
~1.2.3 Allowable Range |
|---|---|---|---|
^ |
Compatible with minor versions | >=1.2.3 <2.0.0 |
— |
~ |
Compatibility Patch Version | — | >=1.2.3 <1.3.0 |
>= |
Greater than or equal to | >=1.2.3 |
— |
> |
Greater than | >1.2.3 |
— |
x |
Wildcard | 1.2.x → >=1.2.0 <1.3.0 |
— |
▶ Example: Actual Results for Different Ranges
{
"express": "^4.18.2",
"lodash": "~4.17.21",
"axios": ">=1.6.0",
"debug": "4.3.x"
}
(3) Version Update Rules
- PATCH: Fixes bugs without changing the API
- MINOR (minor release): New features, backward compatible
- MAJOR (Major Version): Breaking changes; not backward compatible
6. Global Installation vs. Local Installation
(1) Local Installation
By default, the package is installed in the node_modules project; different projects can use different versions.
(2) Global Installation
Add the -g flag to install the package to the system's global directory and provide a command-line tool.
▶ Example: Installing a command-line tool globally
npm install -g nodemon
(3) When to Use a Global Installation
Install only tools that require command-line access (such as nodemon and pm2); project dependencies should always be installed locally.
| Comparison | Local Installation | Global Installation (-g) |
|---|---|---|
| Installation Location | Project node_modules |
System Global Directory |
| package.json | Include dependencies | Do not include |
| Version Isolation | Independent Across Projects | Same Version Shared Globally |
| Use Cases | Project Runtime Dependencies | CLI Tools |
| Unload command | npm uninstall <pkg> |
npm uninstall -g <pkg> |
| Typical packages | express, lodash | nodemon, pm2, typescript |
7. npm scripts
(1) Built-in Scripts
start and test are built-in npm scripts that can be run directly using npm start / npm test.
(2) Custom Scripts
Other scripts must be executed using npm run <name>.
▶ Example: Configuring Common Scripts
{
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest --coverage",
"lint": "eslint src/"
}
}
npm start
npm run dev
npm test
npm run lint
(3) Hooks Between Scripts
pre<script> and post<script> are automatically executed before and after the target script.
▶ Example: Using the pre hook
{
"scripts": {
"prebuild": "npm run lint",
"build": "node build.js",
"postbuild": "echo Build complete"
}
}
Running npm run build will execute prebuild → build → postbuild in sequence.
| Script | Command | Description |
|---|---|---|
| start | npm start |
Launch App |
| test | npm test |
Run Test |
| dev | npm run dev |
Development Mode (Custom) |
| lint | npm run lint |
Code Check (Custom) |
8. The npx Command
(1) Temporarily execute a remote package
npx Allows you to run uninstalled packages directly, preventing global contamination.
▶ Example: Using create-react-app on a temporary basis
npx create-react-app my-app
(2) Run a command on a locally installed system
npx will first check for node_modules/.bin locally, then globally, and finally download it remotely.
▶ Example: Running a local tool
npx jest
(3) Run a specific version
▶ Example: Using a Specific Version of a Package
npx express-generator@4 --view=ejs my-site
9. .npmrc Configuration
(1) Configuration File Hierarchy
.npmrc Supports three levels: project-level, user-level, and global-level, in descending order of priority.
▶ Example: Configuring mirror sources in a project-level .npmrc file
registry=https://registry.npmmirror.com
(2) Common Configuration Options
| Configuration Option | Function | Example Value |
|---|---|---|
| registry | Specify download source | https://registry.npmmirror.com |
| save-prefix | Default version prefix | ^ or ~ |
| prefix | Global installation path | /usr/local |
| cache | Cache Directory | ~/.npm |
▶ Example: Setting the configuration using a command
npm config set registry https://registry.npmmirror.com
npm config get registry
npm config list
10. The "npm install" Execution Process
flowchart TD
A[npm install] --> B{Does package-lock.json exist?}
B -- Yes --> C[Read exact version from lock file]
B -- No --> D[Analyze version ranges in package.json]
D --> E[Search registry for latest compatible version]
E --> F[Generate dependency tree]
C --> G[Download package to cache]
F --> G
G --> H[Write to node_modules]
H --> I[Update package-lock.json]
I --> J[Installation Complete]
11. Comprehensive Example: Setting Up Project Dependencies from Scratch
The following example demonstrates the complete process of how Alice creates a project from scratch, installs dependencies, configures scripts, and starts the development server.
mkdir alice-server && cd alice-server
npm init -y
npm install express luxon
npm install jest nodemon --save-dev
package.json after installation:
{
"name": "alice-server",
"version": "1.0.0",
"description": "Alice's date-aware HTTP server",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest"
},
"dependencies": {
"express": "^4.18.2",
"luxon": "^3.4.4"
},
"devDependencies": {
"jest": "^29.7.0",
"nodemon": "^3.0.2"
},
"license": "ISC"
}
Create the entry file index.js:
const express = require('express');
const { DateTime } = require('luxon');
const app = express();
const PORT = 3000;
app.get('/', (req, res) => {
const now = DateTime.now().toISO();
res.json({ message: 'Server is running', timestamp: now });
});
app.listen(PORT, () => {
console.log(`Server listening on port ${PORT}`);
});
Start the development server:
npm run dev
[nodemon] starting node index.js
Server listening on port 3000
❓ FAQ
package-lock.json be committed to Git?node_modules be committed to Git?npm install, so it should be added to .gitignore.npx and npm exec?npm exec is the equivalent command provided by npm v7 and later; they function identically, but npx is shorter and backward-compatible.npm list to view your local dependency tree, and npm outdated to check which packages have updates.npm install fails with an EACCES permission error?sudo. We recommend setting the global directory to a user-writable path using npm config set prefix.npm install installs "dependencies" by default; you must use the --production flag to skip "devDependencies."📖 Summary
- Use
npm initto initialize the project; use-yto skip the prompts - install/uninstall manage dependencies, -D writes to devDependencies
- package-lock.json locks down specific versions; must be committed
- SemVer uses ^/~/>= to control version ranges
- Global installations are for CLI tools only; all project dependencies must be installed locally.
- npm scripts simplify common commands; "start" and "test" can be omitted in favor of "run"
- npx: Run remote packages temporarily without needing a global installation
- .npmrc supports three levels of configuration: project, user, and global
📝 Exercises
- Run
npm init -yto create a project, then manually edit the name, description, and scripts in package.json - Install
expressandluxonas dependencies, and installjestas a devDependency, then observe the changes to package.json - Use
npm listandnpm outdatedto check the dependency status, respectively - Create the
.npmrcfile, set the registry tohttps://registry.npmmirror.com, and reinstall to verify. - Write a custom script
hellothat outputs "Hello from npm scripts," and run it usingnpm run hello