npm & package.json
npm is Node’s package manager. It installs libraries from a registry of millions of packages and records them in package.json.
package.json
This file is your project’s identity card:
{
"name": "my-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"start": "node src/index.js",
"dev": "node --watch src/index.js"
},
"dependencies": {
"express": "^5.0.0"
}
}
Installing Packages
npm install express # add a runtime dependency
npm install --save-dev vitest # add a dev-only dependency
npm install # install everything from package.json
npm uninstall express # remove a dependency
- dependencies ship with your app.
- devDependencies are only for development (test runners, linters).
Scripts
Scripts are shortcuts you run with npm run:
npm run dev
npm run start
start and test are special — you can drop the word run.
Semantic Versioning
Versions look like MAJOR.MINOR.PATCH — 2.4.1:
- MAJOR — breaking changes.
- MINOR — new features, backwards compatible.
- PATCH — bug fixes.
A caret range ^2.4.1 allows 2.x.x; a tilde ~2.4.1 allows 2.4.x.
The Lockfile
package-lock.json records the exact version of every package, including indirect ones. Commit it so every machine and CI run installs identical code.
npm ci # clean, reproducible install from the lockfile
Use npm ci in CI — it is faster and never rewrites the lockfile.
Best Practices
- Commit the lockfile — Reproducible builds matter.
- Use
npm ciin CI — Deterministic and fast. - Keep dependencies lean — Every package is code you now own.
- Audit occasionally —
npm auditflags known vulnerabilities.
Common Mistakes
- Committing
node_modules— Never; it is reinstallable. - Deleting the lockfile — You lose reproducibility.
- Using
*versions — You get surprise breaking changes. - Installing dev tools as dependencies — They bloat production.