Dependencies vs DevDependencies
Understanding the difference between dependencies and devDependencies is crucial for managing packages correctly.
The Key Difference
| Field | Purpose | When Installed |
|---|---|---|
dependencies | Required to run your app | Always |
devDependencies | Required to develop your app | Development only |
dependencies
Packages your application needs at runtime:
{
"dependencies": {
"express": "^4.18.2",
"mongoose": "^8.0.0",
"bcrypt": "^5.1.0"
}
}
Examples:
- Web frameworks (Express, Fastify)
- Database clients (Mongoose, pg)
- Utility libraries (Lodash, date-fns)
- Authentication libraries
- Any code that runs in production
devDependencies
Packages only needed during development:
{
"devDependencies": {
"jest": "^29.7.0",
"eslint": "^8.55.0",
"typescript": "^5.3.0"
}
}
Examples:
- Testing frameworks (Jest, Vitest, Mocha)
- Linters (ESLint, Prettier)
- Build tools (Webpack, Vite, esbuild)
- Type definitions (@types/*)
- Development servers
Installing to Each Category
# Add to dependencies (default)
npm install express
# Add to devDependencies
npm install jest --save-dev
npm install eslint -D # shorthand
Why Does It Matter?
1. Production Bundle Size
When deploying, you can skip devDependencies:
npm install --production
# or
npm ci --omit=dev
This significantly reduces:
- Deployment size
- Install time
- Security surface area
2. Clear Intent
Other developers understand which packages are essential vs. development tools.
3. Library Publishing
When someone installs your library:
dependenciesare installeddevDependenciesare NOT installed
Decision Guide
Ask yourself: "Does my production code import this package?"
// If your code does this:
import express from 'express';
// → express goes in dependencies
// If only your test files do this:
import { describe, it } from 'jest';
// → jest goes in devDependencies
Common Categorizations
Practice: Categorize These Packages
For each package, decide: dependencies or devDependencies?
| Package | Purpose | Category |
|---|---|---|
| react | UI library | dependencies |
| webpack | Bundler | devDependencies |
| axios | HTTP client | dependencies |
| @testing-library/react | Testing | devDependencies |
| lodash | Utility functions | dependencies |
| typescript | Type checking | devDependencies |
| dotenv | Environment variables | dependencies |
| husky | Git hooks | devDependencies |
Edge Cases
TypeScript Type Definitions
Types are only used at compile time:
npm install -D @types/node @types/express
Build Tools That Run in Production
Some tools like Next.js need to be in dependencies:
{
"dependencies": {
"next": "^14.0.0",
"react": "^18.2.0"
}
}
Peer Dependencies
For plugins and libraries:
{
"peerDependencies": {
"react": ">=17.0.0"
}
}
The host project must provide these.
Moving Packages Between Categories
Accidentally installed in the wrong place?
# Move from dependencies to devDependencies
npm uninstall lodash
npm install lodash -D
# Or edit package.json directly and run npm install
Production Install Commands
# Skip devDependencies
npm install --production
# In npm ci
npm ci --omit=dev
# Using NODE_ENV
NODE_ENV=production npm install
Key Takeaways
- dependencies = needed to run your app
- devDependencies = needed to develop your app
- Use -D flag for devDependencies
- Production deploys should omit devDependencies
- When in doubt, ask: "Does production code import this?"
What's Next?
Now let's learn about semantic versioning (semver) and how version numbers work in npm.

