npm Deep Dive
npm (Node Package Manager) is the world's largest software registry. Understanding how to manage dependencies, version packages, and organize monorepos is essential for professional Node.js development.
📦 npm Ecosystem
2M+ Packages
Largest open-source registry in the world
package.json
Project manifest: deps, scripts, metadata
Lock Files
Ensures reproducible installs across teams
package.json Deep Dive
{
"name": "@myorg/api-server",
"version": "2.1.0",
"description": "Production REST API server",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"engines": {
"node": ">=18.0.0"
},
"scripts": {
"dev": "tsx watch src/index.ts",
"build": "tsc",
"start": "node dist/index.js",
"test": "vitest",
"test:coverage": "vitest --coverage",
"lint": "eslint src/",
"format": "prettier --write src/",
"prepare": "husky install",
"precommit": "lint-staged",
"db:migrate": "prisma migrate dev",
"db:seed": "tsx prisma/seed.ts"
},
"dependencies": {
"express": "^4.18.0",
"prisma": "^5.0.0",
"zod": "^3.22.0"
},
"devDependencies": {
"typescript": "^5.3.0",
"vitest": "^1.0.0",
"@types/express": "^4.17.0",
"tsx": "^4.7.0"
},
"peerDependencies": {
"react": ">=18.0.0"
},
"peerDependenciesMeta": {
"react": { "optional": true }
},
"files": ["dist/", "README.md"],
"repository": {
"type": "git",
"url": "https://github.com/myorg/api-server"
},
"license": "MIT"
}
Semantic Versioning (SemVer)
// Version format: MAJOR.MINOR.PATCH
// 2.1.0
// MAJOR: Breaking changes (2.0.0 -> 3.0.0)
// MINOR: New features, backward compatible (2.1.0 -> 2.2.0)
// PATCH: Bug fixes, backward compatible (2.1.0 -> 2.1.1)
// Version ranges in package.json:
// "^4.18.0" -> >=4.18.0 <5.0.0 (most common, minor + patch updates)
// "~4.18.0" -> >=4.18.0 <4.19.0 (patch updates only)
// "4.18.0" -> exactly 4.18.0 (pinned)
// ">=4.18.0" -> 4.18.0 or higher
// "*" -> any version
// Check outdated packages
// npm outdated
// Update within semver ranges
// npm update
// Update to latest (may include breaking changes)
// npx npm-check-updates -u && npm install
// View package info
// npm view express versions
// npm view express dependencies
Lock Files and Reproducible Builds
// package-lock.json locks EXACT versions of every dependency
// ALWAYS commit lock files to version control
// .gitignore should NOT include package-lock.json
// npm install -> reads package.json, updates lock file
// npm ci -> reads lock file only (faster, reproducible)
// In CI/CD pipelines, ALWAYS use npm ci:
// - Deletes node_modules first
// - Installs exact versions from lock file
// - Fails if lock file is out of sync with package.json
// Example CI step:
// npm ci --production # Skip devDependencies in production
// Managing multiple package managers:
// corepack enable
// corepack prepare pnpm@latest --activate
// Compare: npm vs pnpm vs yarn
// npm - default, widely used, flat node_modules
// pnpm - fastest, strict dependencies, content-addressable store
// yarn - plug'n'play, zero-installs, workspaces pioneer
Workspaces for Monorepos
// Root package.json
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*",
"apps/*"
]
}
// Structure:
// my-monorepo/
// packages/
// shared-utils/package.json ("name": "@myorg/utils")
// database/package.json ("name": "@myorg/database")
// apps/
// web/package.json
// api/package.json
// Install dependencies for all workspaces
// npm install
// Run scripts in specific workspace
// npm run build -w packages/shared-utils
// npm test -w apps/api
// Run scripts in all workspaces
// npm run build --workspaces
// Add dependency to specific workspace
// npm install lodash -w apps/api
// Cross-workspace dependencies
// In apps/api/package.json:
{
"dependencies": {
"@myorg/utils": "*",
"@myorg/database": "*"
}
}
Publishing Packages and npx
// Prepare for publishing
// 1. Set up package.json "files" field (whitelist)
// 2. Add .npmignore for anything not in "files"
// 3. Build before publishing
// Publish to npm
// npm login
// npm publish # public package
// npm publish --access=public # scoped public package
// Use a private registry
// .npmrc
// registry=https://npm.mycompany.com/
// //npm.mycompany.com/:_authToken=${NPM_TOKEN}
// Version bump and publish
// npm version patch # 1.0.0 -> 1.0.1
// npm version minor # 1.0.0 -> 1.1.0
// npm version major # 1.0.0 -> 2.0.0
// npm publish
// npx: run packages without installing
// npx create-next-app my-app
// npx tsx script.ts
// npx -p @angular/cli ng new my-app
// Dependency auditing
// npm audit # Check for vulnerabilities
// npm audit fix # Auto-fix compatible issues
// npm audit fix --force # Fix with breaking changes (careful!)
// Override vulnerable transitive dependencies
{
"overrides": {
"vulnerable-pkg": ">=2.0.1"
}
}
💡 Key Takeaways
- • Always commit lock files; use
npm ciin CI/CD - • Understand SemVer:
^allows minor updates,~allows patch updates - • Use workspaces for monorepo management
- • Run
npm auditregularly to find vulnerabilities - • Use
npxto run CLI tools without global installs