Engineering
Package Management
npm, pnpm, yarn, and effective dependency management strategies
Package Management
Package managers handle dependencies, scripts, and project configuration. Choosing the right one impacts performance and developer experience.
Manager Comparison
| Feature | npm | pnpm | yarn |
|---|---|---|---|
| Disk Usage | High | Low | Medium |
| Install Speed | Medium | Fast | Fast |
| Monorepo Support | Workspaces | Best | Workspaces |
| Lock File | package-lock.json | pnpm-lock.yaml | yarn.lock |
| Strictness | Loose | Strict | Medium |
pnpm (Recommended)
pnpm uses a content-addressable store and hard links, significantly reducing disk space and install time.
Basic Commands
# Install dependencies
pnpm install
# Add a dependency
pnpm add lodash
pnpm add -D typescript # devDependency
pnpm add -g serve # global
# Remove a dependency
pnpm remove lodash
# Update dependencies
pnpm update
pnpm update lodash
pnpm update --latest # ignore semver
# Run scripts
pnpm run build
pnpm build # shorthand
pnpm dev
# Execute binaries
pnpm exec eslint .
pnpm dlx create-vite my-app # like npxpnpm Configuration
# .npmrc
auto-install-peers=true
strict-peer-dependencies=false
shamefully-hoist=true # for compatibility
# Specify registry
registry=https://registry.npmmirror.comWorkspaces (Monorepo)
# pnpm-workspace.yaml
packages:
- 'packages/*'
- 'apps/*'
- '!**/test/**'# Install dependency for specific package
pnpm add lodash --filter @myorg/utils
# Run script in specific package
pnpm --filter @myorg/web build
# Run script in all packages
pnpm -r build
# Run script in packages that changed
pnpm -r --filter "...[origin/main]" buildnpm
npm is the default package manager for Node.js.
Basic Commands
# Install dependencies
npm install
npm ci # clean install (CI environments)
# Add a dependency
npm install lodash
npm install -D typescript
npm install -g serve
# Remove a dependency
npm uninstall lodash
# Update dependencies
npm update
npm update lodash
# Run scripts
npm run build
npm run dev
# Execute binaries
npx eslint .
npx create-vite my-appnpm Configuration
# .npmrc
registry=https://registry.npmmirror.com
save-exact=true
engine-strict=trueyarn
yarn provides speed improvements and additional features over npm.
Basic Commands
# Install dependencies
yarn install
yarn install --frozen-lockfile # CI
# Add a dependency
yarn add lodash
yarn add -D typescript
yarn global add serve
# Remove a dependency
yarn remove lodash
# Update dependencies
yarn upgrade
yarn upgrade lodash
# Run scripts
yarn build
yarn dev
# Execute binaries
yarn dlx create-vite my-apppackage.json Best Practices
{
"name": "@myorg/web-app",
"version": "1.0.0",
"private": true,
"type": "module",
"engines": {
"node": ">=18.0.0",
"pnpm": ">=8.0.0"
},
"packageManager": "pnpm@8.15.0",
"scripts": {
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview",
"lint": "eslint . --ext .ts,.tsx",
"lint:fix": "eslint . --ext .ts,.tsx --fix",
"format": "prettier --write .",
"type-check": "tsc --noEmit",
"test": "vitest",
"test:coverage": "vitest --coverage",
"prepare": "husky install"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
},
"peerDependencies": {
"react": ">=17.0.0"
},
"peerDependenciesMeta": {
"react": {
"optional": false
}
}
}Version Ranges
{
"dependencies": {
"exact": "1.2.3", // Exact version
"patch": "~1.2.3", // 1.2.x (patch updates)
"minor": "^1.2.3", // 1.x.x (minor updates)
"major": "*", // Any version
"range": ">=1.0.0 <2.0.0", // Range
"latest": "latest", // Latest version
"git": "git://github.com/user/repo.git",
"local": "file:../my-lib"
}
}Lock Files
Lock files ensure consistent installs across environments.
# Commit lock files to git
# .gitignore should NOT include:
# - package-lock.json
# - pnpm-lock.yaml
# - yarn.lock
# Use --frozen-lockfile in CI
pnpm install --frozen-lockfile
npm ci
yarn install --frozen-lockfileDependency Auditing
# Check for vulnerabilities
pnpm audit
npm audit
yarn audit
# Auto-fix vulnerabilities
pnpm audit --fix
npm audit fix
yarn audit --fix
# Update vulnerable packages
pnpm update --latestMonorepo Structure
my-monorepo/
├── package.json
├── pnpm-workspace.yaml
├── packages/
│ ├── ui/
│ │ ├── package.json
│ │ └── src/
│ ├── utils/
│ │ ├── package.json
│ │ └── src/
│ └── config/
│ ├── package.json
│ └── src/
├── apps/
│ ├── web/
│ │ ├── package.json
│ │ └── src/
│ └── mobile/
│ ├── package.json
│ └── src/
└── tools/
└── scripts/Internal Dependencies
// apps/web/package.json
{
"name": "@myorg/web",
"dependencies": {
"@myorg/ui": "workspace:*",
"@myorg/utils": "workspace:^1.0.0"
}
}Best Practices
Package Management Guidelines
- Use
pnpmfor disk efficiency and speed - Always commit lock files to version control
- Use exact versions for critical dependencies
- Run
auditregularly to check vulnerabilities - Define
enginesto specify Node.js version - Use
packageManagerfield for consistency - Prefer
workspace:*for monorepo internal deps - Keep dependencies up to date with automated tools