Monorepo in Action: A Deep Dive into Turborepo + pnpm Workspace Configuration
Monorepo in Action: A Deep Dive into Turborepo + pnpm Workspace Configuration
Introduction: Why Choose Monorepo?
In modern frontend development, as project complexity grows, traditional multi-repo management approaches increasingly reveal inefficiencies and dependency management chaos. Monorepo (single repository) addresses these issues by housing multiple related projects in a unified codebase, offering superior code sharing, dependency management, and collaboration.
This article explores how to set up an efficient Monorepo environment using Turborepo and pnpm workspace, with special focus on cross-project dependency optimization strategies.
1. Foundation Setup
1. Initialize Project
mkdir my-monorepo && cd my-monorepo
pnpm init
2. Configure pnpm Workspace
Create pnpm-workspace.yaml
in the root directory:
packages:
- 'apps/*'
- 'packages/*'
- 'libs/*'
This structure separates applications (apps), shared packages (packages), and libraries (libs) for better code organization.
2. Turborepo Configuration
1. Install Turborepo
pnpm add -Dw turbo
2. Configure turbo.json
{
"pipeline": {
"build": {
"outputs": ["dist/**"],
"dependsOn": ["^build"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false
}
}
}
3. Cross-Project Dependency Optimization Strategies
1. Implicit Dependency Management
Different projects may depend on the same base libraries. Using pnpm's workspace protocol ensures all projects use local versions:
{
"dependencies": {
"shared-utils": "workspace:*"
}
}
2. Task Caching & Incremental Builds
Turborepo automatically caches task results based on file hashes. Proper configuration of dependsOn
and outputs
enables efficient incremental builds:
{
"build": {
"outputs": ["dist/**"],
"dependsOn": ["^build"],
"inputs": ["src/**/*.ts", "tsconfig.json"]
}
}
3. Dependency Hoisting Optimization
pnpm's hoist
configuration reduces duplicate dependencies:
# .npmrc
hoist-pattern[]=*eslint*
hoist-pattern[]=*babel*
4. Selective Dependency Installation
Use pnpm's --filter
parameter to install dependencies for specific projects only:
pnpm --filter app1 add react
4. Advanced Optimization Techniques
1. Shared TS Configuration
Create a base tsconfig.json
in the root directory for projects to extend:
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "./dist"
}
}
2. Unified Code Style
Configure ESLint and Prettier at root level for shared usage:
packages/
eslint-config-custom/
tsconfig/
3. Dependency Visualization
Analyze dependencies with pnpm why
:
pnpm why react --filter app1
5. Practical Example
Consider a Monorepo with three projects:
my-monorepo/
├── apps/
│ ├── web-app/
│ └── mobile-app/
├── packages/
│ ├── shared-ui/
│ └── shared-utils/
└── turbo.json
When modifying shared-ui
, Turborepo automatically identifies dependencies and only rebuilds projects relying on shared-ui
, not the entire codebase.
6. Performance Comparison
Compared to traditional multi-repo, our optimized solution shows significant improvements:
Metric | Multi-repo | Optimized Monorepo |
---|---|---|
Dep Install Time | 5min | 1min |
Build Time | 8min | 2min (incremental) |
Disk Usage | 4GB | 1.5GB |
Conclusion
By combining Turborepo and pnpm workspace, we've built an efficient, maintainable Monorepo environment. Cross-project dependency optimization strategies not only boost development efficiency but also ensure dependency consistency. These optimizations yield greater benefits as projects scale.