Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
4.2 KiB
Dependency Management
Best practices for managing dependencies in a Turborepo monorepo.
Core Principle: Install Where Used
Dependencies belong in the package that uses them, not the root.
# Good: Install in specific package
pnpm add react --filter=@repo/ui
pnpm add next --filter=web
# Avoid: Installing in root
pnpm add react -w # Only for repo-level tools!
Benefits of Local Installation
1. Clarity
Each package's package.json lists exactly what it needs:
// packages/ui/package.json
{
"dependencies": {
"react": "^18.0.0",
"class-variance-authority": "^0.7.0"
}
}
2. Flexibility
Different packages can use different versions when needed:
// packages/legacy-ui/package.json
{ "dependencies": { "react": "^17.0.0" } }
// packages/ui/package.json
{ "dependencies": { "react": "^18.0.0" } }
3. Better Caching
Installing in root changes workspace lockfile, invalidating all caches.
4. Pruning Support
turbo prune can remove unused dependencies for Docker images.
What Belongs in Root
Only repository-level tools:
// Root package.json
{
"devDependencies": {
"turbo": "latest",
"husky": "^8.0.0",
"lint-staged": "^15.0.0"
}
}
NOT application dependencies:
- react, next, express
- lodash, axios, zod
- Testing libraries (unless truly repo-wide)
Installing Dependencies
Single Package
# pnpm
pnpm add lodash --filter=@repo/utils
# npm
npm install lodash --workspace=@repo/utils
# yarn
yarn workspace @repo/utils add lodash
# bun
cd packages/utils && bun add lodash
Multiple Packages
# pnpm
pnpm add jest --save-dev --filter=web --filter=@repo/ui
# npm
npm install jest --save-dev --workspace=web --workspace=@repo/ui
# yarn (v2+)
yarn workspaces foreach -R --from '{web,@repo/ui}' add jest --dev
Internal Packages
# pnpm
pnpm add @repo/ui --filter=web
# This updates package.json:
{
"dependencies": {
"@repo/ui": "workspace:*"
}
}
Keeping Versions in Sync
Option 1: Tooling
# syncpack - Check and fix version mismatches
npx syncpack list-mismatches
npx syncpack fix-mismatches
# manypkg - Similar functionality
npx @manypkg/cli check
npx @manypkg/cli fix
# sherif - Rust-based, very fast
npx sherif
Option 2: Package Manager Commands
# pnpm - Update everywhere
pnpm up --recursive typescript@latest
# npm - Update in all workspaces
npm install typescript@latest --workspaces
Option 3: pnpm Catalogs (pnpm 9.5+)
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
catalog:
react: ^18.2.0
typescript: ^5.3.0
// Any package.json
{
"dependencies": {
"react": "catalog:" // Uses version from catalog
}
}
Internal vs External Dependencies
Internal (Workspace)
// pnpm/bun
{ "@repo/ui": "workspace:*" }
// npm/yarn
{ "@repo/ui": "*" }
Turborepo understands these relationships and orders builds accordingly.
External (npm Registry)
{ "lodash": "^4.17.21" }
Standard semver versioning from npm.
Peer Dependencies
For library packages that expect the consumer to provide dependencies:
// packages/ui/package.json
{
"peerDependencies": {
"react": "^18.0.0",
"react-dom": "^18.0.0"
},
"devDependencies": {
"react": "^18.0.0", // For development/testing
"react-dom": "^18.0.0"
}
}
Common Issues
"Module not found"
- Check the dependency is installed in the right package
- Run
pnpm install/npm installto update lockfile - Check exports are defined in the package
Version Conflicts
Packages can use different versions - this is a feature, not a bug. But if you need consistency:
- Use tooling (syncpack, manypkg)
- Use pnpm catalogs
- Create a lint rule
Hoisting Issues
Some tools expect dependencies in specific locations. Use package manager config:
# .npmrc (pnpm)
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
Lockfile
Required for:
- Reproducible builds
- Turborepo dependency analysis
- Cache correctness
# Commit your lockfile!
git add pnpm-lock.yaml # or package-lock.json, yarn.lock