npm supports multiple dependency types, each with different roles and use cases in package.json.
Dependency Types
1. dependencies (Production Dependencies)
Dependencies required for the application to run, needed when deploying to production.
json{ "dependencies": { "express": "^4.18.0", "lodash": "^4.17.21", "axios": "^1.0.0" } }
Installation Commands:
bashnpm install <package> npm install <package> --save-prod npm install <package> -P
Use Cases:
- Web frameworks (Express, React, Vue)
- Utility libraries (lodash, moment)
- API clients (axios, fetch)
2. devDependencies (Development Dependencies)
Dependencies only needed during development, not required in production.
json{ "devDependencies": { "jest": "^29.0.0", "eslint": "^8.0.0", "webpack": "^5.0.0", "nodemon": "^3.0.0" } }
Installation Commands:
bashnpm install <package> --save-dev npm install <package> -D
Use Cases:
- Testing frameworks (Jest, Mocha)
- Code linting tools (ESLint, Prettier)
- Build tools (Webpack, Rollup)
- Development servers (nodemon)
3. peerDependencies (Peer Dependencies)
Dependencies expected to be provided by the host project, not automatically installed.
json{ "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }
Use Cases:
- Plugins or libraries that need the host to provide core libraries
- Avoid installing duplicate versions of the same package
- Ensure compatibility with the host project
Example: React component library
json{ "name": "my-react-components", "peerDependencies": { "react": "^18.0.0", "react-dom": "^18.0.0" } }
4. optionalDependencies (Optional Dependencies)
Dependencies that won't interrupt the installation process if they fail to install.
json{ "optionalDependencies": { "fsevents": "^2.3.0", "chokidar": "^3.5.0" } }
Installation Commands:
bashnpm install <package> --save-optional npm install <package> -O
Use Cases:
- Platform-specific packages (e.g., fsevents for macOS)
- Optional feature enhancement packages
- Dependencies that don't affect core functionality
5. bundledDependencies (Bundled Dependencies)
Dependencies included when bundling, packaged together when publishing.
json{ "bundledDependencies": [ "my-internal-lib" ] }
Notes:
- Must be declared in dependencies or devDependencies
- Cannot be optional dependencies
- Increases package size
Core package.json Fields
Basic Information
json{ "name": "my-project", "version": "1.0.0", "description": "A sample project", "keywords": ["npm", "javascript", "node"], "author": "Your Name <email@example.com>", "license": "MIT", "homepage": "https://github.com/user/repo#readme", "repository": { "type": "git", "url": "https://github.com/user/repo.git" } }
Entry and Configuration
json{ "main": "index.js", "module": "dist/index.esm.js", "types": "dist/index.d.ts", "bin": { "my-cli": "./bin/cli.js" }, "files": [ "dist", "README.md", "LICENSE" ], "directories": { "lib": "lib", "test": "test" } }
Configuration Fields
json{ "config": { "port": 3000, "env": "development" }, "engines": { "node": ">=14.0.0", "npm": ">=6.0.0" }, "os": ["!win32"], "cpu": ["x64", "arm64"] }
Private and Publishing Configuration
json{ "private": true, "publishConfig": { "registry": "https://registry.npmjs.org", "access": "public" } }
Workspaces
npm 7+ supports workspaces for managing monorepos:
json{ "name": "my-monorepo", "version": "1.0.0", "workspaces": [ "packages/*" ], "scripts": { "install": "npm install -ws", "build": "npm run build -ws" } }
Directory Structure:
shellmy-monorepo/ ├── package.json ├── packages/ │ ├── package-a/ │ │ └── package.json │ └── package-b/ │ └── package.json
Dependency Resolution Strategy
npm uses a nested dependency structure (node_modules):
shellnode_modules/ ├── package-a/ │ └── node_modules/ │ └── package-c/ └── package-b/ └── node_modules/ └── package-c/
Resolution Rules:
- First check the current package's node_modules
- Then check the parent package's node_modules
- Recursively search upward until the root directory
Common Issues
1. Dependency Conflicts
When two packages need different versions of the same dependency:
json{ "dependencies": { "package-a": "^1.0.0", // requires lodash@^4.0.0 "package-b": "^2.0.0" // requires lodash@^3.0.0 } }
npm will install two versions of lodash.
2. Dependency Hoisting
npm attempts to hoist dependencies to higher levels to reduce duplication:
shellnode_modules/ ├── lodash/ // hoisted to top level ├── package-a/ └── package-b/
3. Dependency Locking
Use package-lock.json to ensure dependency consistency:
json{ "lockfileVersion": 2, "packages": { "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-..." } } }
Best Practices
- Clearly distinguish dependency types: Use dependencies and devDependencies correctly
- Use peerDependencies: Plugin libraries should use peerDependencies
- Minimize dependencies: Only install necessary packages
- Regular updates: Use
npm outdatedandnpm audit - Lock versions: Commit package-lock.json to version control
- Use workspaces: Use workspaces to manage monorepos for large projects
- Document dependencies: Explain main dependencies and their purposes in README
Common Commands
bash# Install production dependency npm install <package> # Install development dependency npm install <package> -D # Install all dependencies npm install # Install only production dependencies npm install --production # Check for dependency updates npm outdated # Update dependencies npm update # Check for security vulnerabilities npm audit # Automatically fix security vulnerabilities npm audit fix
Understanding npm dependency types and package.json configuration is crucial for managing project dependencies, optimizing package size, and ensuring project stability.