Dependency Management
Master pnpm's powerful dependency management to add, update, and maintain packages across 40+ workspaces efficiently.
Know the basics?
Why proper dependency management matters
Managing dependencies incorrectly in a monorepo causes serious problems:
- Wrong location — Adding packages to root instead of specific workspaces breaks isolation
- Version conflicts — Different packages use incompatible versions of the same dependency
- Phantom dependencies — Code relies on unlisted dependencies, breaking CI
- Bloated installs — Unnecessary dependencies slow down installation
- Security vulnerabilities — Outdated packages expose your apps to attacks
OneApp uses pnpm with workspace-specific dependency management — installing packages exactly where needed, preventing phantom dependencies with strict mode, and using content-addressable storage — ensuring fast, reliable, and secure dependency management.
Use cases
Master dependency management to:
- Add packages efficiently — Install to the right workspace on first try
- Update safely — Review and test updates before merging
- Debug quickly — Find why a package is installed and resolve conflicts
- Maintain security — Keep dependencies up-to-date and vulnerability-free
- Optimize installs — Leverage pnpm's caching for 3x faster installations
How it works
Dependencies are managed at three levels:
{
"root": {
"devDependencies": "Workspace-wide tools (ESLint, TypeScript, Prettier)"
},
"packages": {
"dependencies": "Package-specific runtime dependencies",
"devDependencies": "Package-specific dev tools",
"peerDependencies": "Dependencies provided by consumers"
},
"apps": {
"dependencies": "App-specific dependencies + workspace packages"
}
}Adding dependencies
To a specific workspace
# Production dependency
pnpm --filter=web add lodash
# Development dependency
pnpm --filter=web add -D vitest
# Peer dependency (for libraries)
pnpm --filter=@repo/ui add -P react react-domWhen to use:
- Production dependencies: Required at runtime (React, Next.js, database clients)
- Dev dependencies: Only needed during development (TypeScript, testing tools)
- Peer dependencies: Consumer must provide (React for UI libraries)
To the root workspace
# Add dev dependency to root (workspace-wide tooling only)
pnpm add -D -w prettier eslint typescriptRoot dependencies
Only add to root for tools used across ALL packages:
- ✅ Formatters (Prettier)
- ✅ Linters (ESLint)
- ✅ TypeScript compiler
- ❌ Package-specific dependencies (these go in the package)
Internal dependencies
Internal packages automatically use workspace:*:
# Add internal package
pnpm --filter=web add @repo/ui
# Results in package.json:
# "@repo/ui": "workspace:*"Benefits:
- ✅ Always links to local version during development
- ✅ No version mismatches
- ✅ Changes reflect instantly
- ✅ Converts to real version when publishing
Updating dependencies
Update specific package
# Update to latest compatible version
pnpm --filter=web update lodash
# Update to specific version
pnpm --filter=web update lodash@4.17.21
# Update to latest (ignore semver)
pnpm --filter=web update lodash@latestUpdate all dependencies
# Update all in a workspace
pnpm --filter=web update
# Update all across monorepo
pnpm -r update
# Interactive update (choose which to update)
pnpm --filter=web update -iCheck for outdated packages
# Check outdated in specific workspace
pnpm --filter=web outdated
# Check outdated across all workspaces
pnpm -r outdatedRemoving dependencies
# Remove from workspace
pnpm --filter=web remove lodash
# Remove from root
pnpm remove -w prettier
# Remove dev dependency
pnpm --filter=web remove -D vitestUnderstanding workspace:*
What it means
The workspace:* protocol tells pnpm to:
- Development: Link to local package via symlink
- Type checking: Use local TypeScript types
- Publishing: Convert to actual version (if applicable)
Example workflow
{
"dependencies": {
"@repo/ui": "workspace:*"
}
}What pnpm does:
# During development
node_modules/@repo/ui → symlink to ../../packages/ui
# Your changes in packages/ui/ are immediately available in apps/web/Troubleshooting
Dependency not found
# Clear cache and reinstall
pnpm store prune
pnpm install
# Force reinstall
pnpm install --forceVersion conflicts
# Check why a version is installed
pnpm why lodash
# Shows all packages depending on lodashSolution:
{
"pnpm": {
"overrides": {
"lodash": "4.17.21" // Force this version everywhere
}
}
}Clean reinstall
# Nuclear option - full clean
pnpm clean && pnpm install
# Or manually
rm -rf node_modules
rm -rf **/node_modules
rm pnpm-lock.yaml
pnpm installBest practices
1. Pin exact versions for apps
{
"dependencies": {
"next": "16.0.0", // ✅ Exact version
"react": "19.0.0" // ✅ Exact version
}
}Why: Ensures reproducible builds in production
2. Use ranges for peer dependencies
{
"peerDependencies": {
"react": "^19.0.0" // ✅ Compatible versions
}
}Why: Allows consumers to use compatible versions
3. Keep root deps minimal
{
"devDependencies": {
"prettier": "^3.0.0",
"typescript": "^5.0.0",
"turbo": "^2.0.0"
}
}4. Test after updates
# Full test suite
pnpm build && pnpm lint && pnpm typecheck
# Package-specific
pnpm --filter=web build
pnpm --filter=web testNext steps
- Type safety patterns: Type Safety →
- Workspace architecture: Workspace Architecture →
- Essential commands: Commands →