Module 33: npm and Package Management
npm (Node Package Manager) is the world's largest software registry. Learn to manage dependencies, publish packages, and follow best practices.
1. npm Basics
1.1 Getting Started
# Check npm version
npm --version
npm -v
# Initialize a new project
npm init
# Or use defaults
npm init -y
# Install packages
npm install lodash # Add to dependencies
npm install --save-dev jest # Add to devDependencies
npm install -g nodemon # Install globally
# Shortcuts
npm i lodash # install
npm i -D jest # --save-dev
npm i -g nodemon # --global
# Install specific version
npm install lodash@4.17.21
npm install lodash@^4.17.0 # Compatible version
npm install lodash@~4.17.0 # Patch updates only
npm install lodash@latest # Latest version
# Uninstall packages
npm uninstall lodash
npm uninstall -D jest
npm uninstall -g nodemon
# Update packages
npm update # Update all packages
npm update lodash # Update specific package
npm outdated # Check for outdated packages
1.2 package.json
{
"name": "my-app",
"version": "1.0.0",
"description": "My awesome application",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js",
"test": "jest",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
"build": "webpack --mode production",
"lint": "eslint src/",
"format": "prettier --write \"src/**/*.js\""
},
"keywords": ["node", "api", "rest"],
"author": "Your Name <you@example.com>",
"license": "MIT",
"dependencies": {
"express": "^4.18.2",
"lodash": "^4.17.21"
},
"devDependencies": {
"jest": "^29.0.0",
"nodemon": "^2.0.20",
"eslint": "^8.0.0"
},
"engines": {
"node": ">=16.0.0",
"npm": ">=8.0.0"
},
"repository": {
"type": "git",
"url": "https://github.com/username/repo.git"
},
"bugs": {
"url": "https://github.com/username/repo/issues"
},
"homepage": "https://github.com/username/repo#readme"
}
1.3 Semantic Versioning (SemVer)
// Version format: MAJOR.MINOR.PATCH
// 1.2.3
// │ │ └─ Patch: Bug fixes (backwards compatible)
// │ └─── Minor: New features (backwards compatible)
// └───── Major: Breaking changes
// Version ranges
"express": "4.18.2" // Exact version
"express": "^4.18.2" // Compatible (^) - allows 4.x.x (not 5.0.0)
"express": "~4.18.2" // Approximately (~) - allows 4.18.x (not 4.19.0)
"express": "*" // Any version (not recommended)
"express": ">=4.0.0" // Greater than or equal
"express": "<5.0.0" // Less than
"express": "4.x" // Any 4.x.x version
// Multiple conditions
"express": ">=4.0.0 <5.0.0"
// Examples
"^1.2.3" // Allows: 1.2.3, 1.2.4, 1.3.0, 1.9.9 (not 2.0.0)
"~1.2.3" // Allows: 1.2.3, 1.2.4, 1.2.9 (not 1.3.0)
Version Ranges
^ (caret) is most common - allows minor and patch updates. ~ (tilde) is more conservative - only patch updates.
2. npm Scripts
2.1 Common Scripts
{
"scripts": {
// Development
"dev": "nodemon src/index.js",
"start": "node src/index.js",
// Testing
"test": "jest",
"test:unit": "jest --testPathPattern=unit",
"test:integration": "jest --testPathPattern=integration",
"test:watch": "jest --watch",
"test:coverage": "jest --coverage",
// Building
"build": "webpack --mode production",
"build:dev": "webpack --mode development",
"prebuild": "npm run clean", // Runs before build
"postbuild": "npm run copy-files", // Runs after build
// Linting & Formatting
"lint": "eslint src/",
"lint:fix": "eslint src/ --fix",
"format": "prettier --write \"src/**/*.{js,json,md}\"",
"format:check": "prettier --check \"src/**/*.{js,json,md}\"",
// Utilities
"clean": "rm -rf dist",
"deploy": "npm run build && npm run upload",
// Pre and post hooks
"pretest": "npm run lint",
"posttest": "npm run coverage"
}
}
2.2 Running Scripts
# Run scripts
npm run dev
npm run test
npm run build
# Special scripts (no 'run' needed)
npm start
npm test
npm stop
# Pass arguments to scripts
npm run test -- --watch
npm run build -- --mode production
# Run multiple scripts
npm run lint && npm run test # Sequential
npm run lint & npm run test # Parallel (use npm-run-all for better support)
# Using npm-run-all
npm install --save-dev npm-run-all
# In package.json
{
"scripts": {
"clean": "rm -rf dist",
"build:js": "webpack",
"build:css": "postcss src/styles.css -o dist/styles.css",
"build": "npm-run-all clean build:*" # Run all build:* scripts
}
}
# Silent mode
npm run test --silent
# View script code
npm run
npm run-script
2.3 Environment Variables
{
"scripts": {
"dev": "NODE_ENV=development node index.js",
"prod": "NODE_ENV=production node index.js"
}
}
// In your code
const env = process.env.NODE_ENV || 'development';
console.log(`Running in ${env} mode`);
// Cross-platform (Windows compatible)
// npm install --save-dev cross-env
{
"scripts": {
"dev": "cross-env NODE_ENV=development node index.js",
"prod": "cross-env NODE_ENV=production node index.js"
}
}
3. Package Management
3.1 package-lock.json
// package-lock.json ensures consistent installs
// - Locks exact versions of all dependencies
// - Includes nested dependencies
// - Should be committed to version control
// Example structure
{
"name": "my-app",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "my-app",
"version": "1.0.0",
"dependencies": {
"express": "^4.18.2"
}
},
"node_modules/express": {
"version": "4.18.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
"integrity": "sha512-...",
"dependencies": {
"accepts": "~1.3.8",
"body-parser": "1.20.1"
}
}
}
}
// Commands
npm ci # Clean install (uses package-lock.json, faster for CI)
npm install # Install with package.json (updates package-lock.json)
3.2 .npmrc Configuration
# .npmrc file (project or global)
# Registry
registry=https://registry.npmjs.org/
# Scoped packages
@myorg:registry=https://registry.myorg.com/
# Authentication
//registry.npmjs.org/:_authToken=${NPM_TOKEN}
# Save exact versions
save-exact=true
# Use package-lock.json
package-lock=true
# Engine strict
engine-strict=true
# Progress
progress=false
# Audit
audit=true
audit-level=moderate
# Global .npmrc location
# Windows: C:\Users\{username}\.npmrc
# macOS/Linux: ~/.npmrc
# Project .npmrc location
# {project-root}/.npmrc
3.3 node_modules
# Understanding node_modules
node_modules/
├── express/
│ ├── package.json
│ ├── index.js
│ └── node_modules/ # Nested dependencies
│ ├── body-parser/
│ └── cookie/
├── lodash/
└── jest/
# Clean install
rm -rf node_modules package-lock.json
npm install
# Or use npm ci (faster, cleaner for CI/CD)
npm ci
# Prune unused packages
npm prune
# Check for issues
npm doctor
# Find duplicate packages
npm dedupe
.gitignore
Always add node_modules/ to .gitignore. Never commit dependencies to git - use package.json and package-lock.json instead.
4. Publishing Packages
4.1 Creating a Package
// 1. Create package
mkdir my-awesome-package
cd my-awesome-package
npm init
// 2. Write code
// index.js
function greet(name) {
return `Hello, ${name}!`;
}
function add(a, b) {
return a + b;
}
module.exports = { greet, add };
// 3. Add README.md
// # My Awesome Package
//
// ## Installation
// ```bash
// npm install my-awesome-package
// ```
//
// ## Usage
// ```javascript
// const { greet } = require('my-awesome-package');
// console.log(greet('World'));
// ```
// 4. Configure package.json
{
"name": "my-awesome-package",
"version": "1.0.0",
"description": "An awesome package",
"main": "index.js",
"scripts": {
"test": "jest"
},
"keywords": ["awesome", "utility"],
"author": "Your Name",
"license": "MIT",
"files": [
"index.js",
"lib/",
"README.md"
],
"repository": {
"type": "git",
"url": "https://github.com/username/my-awesome-package"
}
}
// 5. Add .npmignore (what NOT to publish)
node_modules/
*.test.js
.env
.git
coverage/
.vscode/
// 6. Test locally
npm link # Create global symlink
// In another project
npm link my-awesome-package
4.2 Publishing to npm
# 1. Create npm account
npm signup
# 2. Login
npm login
# 3. Check what will be published
npm pack --dry-run
# 4. Publish
npm publish
# Publish scoped package (public)
npm publish --access public
# Update version 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
# Unpublish (within 72 hours only)
npm unpublish my-awesome-package@1.0.0
# Deprecate version
npm deprecate my-awesome-package@1.0.0 "This version has bugs, use 1.0.1"
4.3 Scoped Packages
// Scoped packages: @username/package-name or @org/package-name
// package.json
{
"name": "@myusername/my-package",
"version": "1.0.0"
}
// Publish
npm publish --access public
// Install
npm install @myusername/my-package
// Use
const pkg = require('@myusername/my-package');
// Private scoped packages (requires paid account)
npm publish // Default is private for scoped packages
5. npm Alternatives
5.1 Yarn
# Install Yarn
npm install -g yarn
# Initialize project
yarn init
# Install packages
yarn add lodash # Add dependency
yarn add --dev jest # Add dev dependency
yarn global add nodemon # Install globally
# Remove packages
yarn remove lodash
# Update packages
yarn upgrade
yarn upgrade lodash
# Install all dependencies
yarn install
# Run scripts
yarn start
yarn test
yarn run build
# yarn.lock (similar to package-lock.json)
# Always commit to version control
5.2 pnpm
# Install pnpm
npm install -g pnpm
# Initialize project
pnpm init
# Install packages
pnpm add lodash # Add dependency
pnpm add -D jest # Add dev dependency
pnpm add -g nodemon # Install globally
# Remove packages
pnpm remove lodash
# Update packages
pnpm update
pnpm update lodash
# Install all dependencies
pnpm install
# Run scripts
pnpm start
pnpm test
pnpm run build
# Benefits
# - Faster than npm and yarn
# - Disk space efficient (hard links)
# - Strict dependency resolution
5.3 Comparison
| Feature | npm | Yarn | pnpm |
|---|---|---|---|
| Speed | Medium | Fast | Fastest |
| Disk Space | Most | More | Least |
| Lock File | package-lock.json | yarn.lock | pnpm-lock.yaml |
| Workspaces | Yes | Yes | Yes |
| PnP | No | Yes | No |
| Market Share | Highest | Medium | Growing |
6. Best Practices
6.1 Security
# Audit packages for vulnerabilities
npm audit
# Fix vulnerabilities automatically
npm audit fix
npm audit fix --force # May include breaking changes
# Check for outdated packages
npm outdated
# Use security tools
npm install -g snyk
snyk test
snyk wizard
# Keep dependencies updated
npm update
# Use exact versions for critical packages
{
"dependencies": {
"express": "4.18.2" // No ^ or ~
}
}
6.2 Performance
// Use npm ci in CI/CD
// package.json
{
"scripts": {
"ci": "npm ci && npm run test"
}
}
// Leverage caching
// In .gitignore
node_modules/
package-lock.json # Don't ignore! Commit it
// In CI (GitHub Actions example)
- name: Cache dependencies
uses: actions/cache@v2
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
// Optimize package size
{
"files": [
"dist/",
"README.md"
]
}
// Tree shaking (use ES modules)
// Use named exports
export function add(a, b) { return a + b; }
// Instead of
module.exports = { add };
6.3 Workspace and Monorepos
// package.json (root)
{
"name": "my-monorepo",
"private": true,
"workspaces": [
"packages/*"
]
}
// packages/package-a/package.json
{
"name": "@myorg/package-a",
"version": "1.0.0",
"dependencies": {
"@myorg/package-b": "1.0.0"
}
}
// packages/package-b/package.json
{
"name": "@myorg/package-b",
"version": "1.0.0"
}
// Install all workspaces
npm install
// Run script in specific workspace
npm run test --workspace=@myorg/package-a
// Run script in all workspaces
npm run test --workspaces
7. Common Packages
7.1 Essential Packages
// Utility libraries
"lodash": "^4.17.21" // Utility functions
"date-fns": "^2.29.3" // Date manipulation
"uuid": "^9.0.0" // Generate UUIDs
// Web frameworks
"express": "^4.18.2" // Web framework
"fastify": "^4.0.0" // Fast web framework
"koa": "^2.14.1" // Next-gen web framework
// Database
"mongoose": "^6.0.0" // MongoDB ODM
"pg": "^8.8.0" // PostgreSQL client
"mysql2": "^3.0.0" // MySQL client
// Validation
"joi": "^17.7.0" // Schema validation
"validator": "^13.7.0" // String validators
"yup": "^0.32.11" // Schema validation
// Authentication
"jsonwebtoken": "^9.0.0" // JWT
"bcryptjs": "^2.4.3" // Password hashing
"passport": "^0.6.0" // Authentication middleware
// Testing
"jest": "^29.0.0" // Testing framework
"mocha": "^10.0.0" // Testing framework
"chai": "^4.3.7" // Assertion library
"supertest": "^6.3.0" // HTTP testing
// Build tools
"webpack": "^5.0.0" // Module bundler
"vite": "^4.0.0" // Build tool
"babel": "^7.0.0" // Transpiler
// Code quality
"eslint": "^8.0.0" // Linter
"prettier": "^2.8.0" // Code formatter
"husky": "^8.0.0" // Git hooks
// Environment
"dotenv": "^16.0.3" // Environment variables
"cross-env": "^7.0.3" // Cross-platform env vars
Summary
In this module, you learned:
- ✅ npm basics and commands
- ✅ package.json configuration
- ✅ Semantic versioning
- ✅ npm scripts and automation
- ✅ Publishing packages
- ✅ Security and auditing
- ✅ npm alternatives (Yarn, pnpm)
- ✅ Best practices and common packages
Next Steps
In Module 34, you'll get an Introduction to TypeScript, adding type safety to your JavaScript.
Practice Exercises
- Create and publish your own npm package
- Set up a monorepo with workspaces
- Create custom npm scripts for your workflow
- Audit and fix vulnerabilities in a project
- Configure ESLint and Prettier via npm
- Build a CLI tool with npm scripts
- Set up automated testing with npm scripts
- Create a project template generator