Files
website-enchun-mgr/.opencode/skills/turborepo/references/best-practices/dependencies.md
pkupuk ad8e2e313e chore(agent): configure AI agents and tools
Add configuration for BMad, Claude, OpenCode, and other AI agent tools and workflows.
2026-02-11 11:51:23 +08:00

247 lines
4.2 KiB
Markdown

# 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.
```bash
# 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:
```json
// 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:
```json
// 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:
```json
// 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
```bash
# 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
```bash
# 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
```bash
# pnpm
pnpm add @repo/ui --filter=web
# This updates package.json:
{
"dependencies": {
"@repo/ui": "workspace:*"
}
}
```
## Keeping Versions in Sync
### Option 1: Tooling
```bash
# 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
```bash
# 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+)
```yaml
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
catalog:
react: ^18.2.0
typescript: ^5.3.0
```
```json
// Any package.json
{
"dependencies": {
"react": "catalog:" // Uses version from catalog
}
}
```
## Internal vs External Dependencies
### Internal (Workspace)
```json
// pnpm/bun
{ "@repo/ui": "workspace:*" }
// npm/yarn
{ "@repo/ui": "*" }
```
Turborepo understands these relationships and orders builds accordingly.
### External (npm Registry)
```json
{ "lodash": "^4.17.21" }
```
Standard semver versioning from npm.
## Peer Dependencies
For library packages that expect the consumer to provide dependencies:
```json
// 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"
1. Check the dependency is installed in the right package
2. Run `pnpm install` / `npm install` to update lockfile
3. 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:
1. Use tooling (syncpack, manypkg)
2. Use pnpm catalogs
3. Create a lint rule
### Hoisting Issues
Some tools expect dependencies in specific locations. Use package manager config:
```yaml
# .npmrc (pnpm)
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*
```
## Lockfile
**Required** for:
- Reproducible builds
- Turborepo dependency analysis
- Cache correctness
```bash
# Commit your lockfile!
git add pnpm-lock.yaml # or package-lock.json, yarn.lock
```