npm's monorepo support is implemented through the workspaces feature, allowing you to manage multiple related packages in a single repository. This is very useful for large projects and team collaboration.
Workspaces Basics
What Are Workspaces
Workspaces allow you to manage multiple packages in a single npm project. These packages can depend on each other and share dependencies.
Basic Configuration
Configure workspaces in the root package.json:
json{ "name": "my-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "packages/*" ], "scripts": { "install": "npm install -ws", "build": "npm run build -ws", "test": "npm test -ws", "clean": "npm run clean -ws" } }
Directory Structure
shellmy-monorepo/ ├── package.json ├── packages/ │ ├── shared/ │ │ ├── package.json │ │ └── index.js │ ├── app/ │ │ ├── package.json │ │ └── index.js │ └── utils/ │ ├── package.json │ └── index.js ├── node_modules/ │ ├── shared/ # Symbolic link to packages/shared │ ├── app/ # Symbolic link to packages/app │ └── utils/ # Symbolic link to packages/utils └── package-lock.json
Workspace Configuration Options
1. Array Format
json{ "workspaces": [ "packages/*", "apps/*" ] }
2. Object Format
json{ "workspaces": { "packages": [ "packages/*" ] } }
3. Mixed Format
json{ "workspaces": { "packages": [ "packages/*", "apps/*" ], "nohoist": [ "**/lodash" ] } }
Workspace Commands
Install Dependencies
bash# Install dependencies in all workspaces npm install -ws npm install --workspaces # Install dependencies in specific workspace npm install lodash --workspace=packages/app npm install lodash -w packages/app # Install workspace dependency npm install ../shared --workspace=packages/app
Run Scripts
bash# Run scripts in all workspaces npm run build -ws npm run build --workspaces # Run scripts in specific workspace npm run build --workspace=packages/app npm run build -w packages/app # Run scripts in multiple workspaces npm run build -w packages/app -w packages/utils
Update Dependencies
bash# Update dependencies in all workspaces npm update -ws # Update dependencies in specific workspace npm update --workspace=packages/app
Remove Dependencies
bash# Remove dependencies from all workspaces npm uninstall lodash -ws # Remove dependencies from specific workspace npm uninstall lodash --workspace=packages/app
Inter-Workspace Dependencies
Add Workspace Dependency
bash# Add dependency on packages/shared in packages/app cd packages/app npm install ../shared # Or use workspace name npm install shared --workspace=packages/app
package.json Example
packages/app/package.json:
json{ "name": "app", "version": "1.0.0", "dependencies": { "shared": "*", "lodash": "^4.17.21" } }
packages/shared/package.json:
json{ "name": "shared", "version": "1.0.0", "dependencies": { "lodash": "^4.17.21" } }
Advanced Configuration
1. nohoist Configuration
Prevent certain packages from being hoisted to the root:
json{ "workspaces": { "packages": [ "packages/*" ], "nohoist": [ "**/lodash", "**/react", "**/webpack" ] } }
2. Private Packages
Ensure workspace packages are not published:
json{ "name": "my-monorepo", "private": true, "workspaces": [ "packages/*" ] }
3. Shared Dependencies
Define shared dependencies in the root:
Root package.json:
json{ "name": "my-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "packages/*" ], "devDependencies": { "jest": "^29.0.0", "eslint": "^8.0.0", "typescript": "^5.0.0" } }
Practical Example
React + Express Monorepo
shellmy-monorepo/ ├── package.json ├── packages/ │ ├── web/ │ │ ├── package.json │ │ └── src/ │ ├── api/ │ │ ├── package.json │ │ └── src/ │ └── shared/ │ ├── package.json │ └── src/
Root package.json:
json{ "name": "my-monorepo", "version": "1.0.0", "private": true, "workspaces": [ "packages/*" ], "scripts": { "install": "npm install -ws", "build": "npm run build -ws", "dev": "npm run dev -ws", "test": "npm test -ws", "lint": "npm run lint -ws" } }
packages/web/package.json:
json{ "name": "web", "version": "1.0.0", "dependencies": { "react": "^18.0.0", "shared": "*" } }
packages/api/package.json:
json{ "name": "api", "version": "1.0.0", "dependencies": { "express": "^4.18.0", "shared": "*" } }
packages/shared/package.json:
json{ "name": "shared", "version": "1.0.0", "dependencies": { "lodash": "^4.17.21" } }
Best Practices
1. Unified Version Management
json{ "scripts": { "version": "npm version --workspaces", "publish": "npm publish --workspaces" } }
2. Shared Configuration
json{ "devDependencies": { "jest": "^29.0.0", "eslint": "^8.0.0", "prettier": "^3.0.0" } }
3. Unified Scripts
json{ "scripts": { "build": "npm run build -ws", "test": "npm test -ws", "lint": "npm run lint -ws", "clean": "npm run clean -ws" } }
4. Use Lerna (Optional)
Lerna is a tool specifically designed for managing JavaScript monorepos:
bash# Install Lerna npm install -g lerna # Initialize Lerna lerna init # Run commands lerna run build lerna publish
Common Issues
1. Dependency Conflicts
bash# Check dependencies npm ls -ws # Use overrides to resolve conflicts npm config set overrides '{"package": "1.2.3"}'
2. Symbolic Link Issues
bash# Check symbolic links ls -la node_modules/ # Reinstall rm -rf node_modules package-lock.json npm install -ws
3. TypeScript Path Issues
tsconfig.json:
json{ "compilerOptions": { "baseUrl": ".", "paths": { "shared": ["packages/shared/src"], "app": ["packages/app/src"] } } }
4. Build Order Issues
bash# Build in order npm run build --workspace=packages/shared npm run build --workspace=packages/app npm run build --workspace=packages/api
Integration with Other Tools
1. TypeScript
json{ "references": [ { "path": "./packages/shared" }, { "path": "./packages/app" } ] }
2. Jest
json{ "projects": [ "<rootDir>/packages/*/jest.config.js" ] }
3. ESLint
json{ "overrides": [ { "files": ["packages/*/src/**/*.ts"], "extends": ["@mycompany/eslint-config"] } ] }
4. Webpack
javascriptmodule.exports = { resolve: { alias: { shared: path.resolve(__dirname, 'packages/shared/src') } } };
Performance Optimization
1. Parallel Builds
bash# Run scripts in parallel npm run build -ws --parallel
2. Incremental Builds
bash# Only build changed packages npm run build -ws --if-present
3. Caching
bash# Use cache npm install -ws --prefer-offline
Monitoring and Debugging
1. View Workspace Information
bash# List all workspaces npm workspaces info # View specific workspace npm workspaces info --workspace=packages/app
2. Debug Dependencies
bash# View dependency tree npm ls -ws # View dependencies of specific package npm ls shared -ws
3. View Installation Logs
bash# Verbose logging npm install -ws --verbose # Debug logging npm install -ws --loglevel=verbose
npm workspaces is a powerful tool for managing monorepos, which can significantly improve development efficiency and maintainability of large projects.