Monorepo vs Multi-Repo: The Front-End Repository Management Playbook
Foreword
In the development of front-end projects, as the business grows and the team expands, the way code repositories are managed is constantly evolving. From early monolithic repositories, to later multi-repo models, and now the popular Monorepo architecture, each management style has its applicable scenarios, advantages, and disadvantages.
For many front-end teams, multi-repo management is an unavoidable topic. When a project scales up and needs to be split into multiple independent repositories, how to efficiently manage dependencies between these repositories, share code, and unify build processes becomes the core challenge facing the team.
This article will take you through the current state, challenges, and solutions of front-end multi-repo management, helping you make the right decisions in real projects and bring multi-repo management from chaos to order.
1. Why Do You Need Multi-Repo Management?
In the early stages of a project, most teams adopt a Single Repo approach, placing all code in one repository. This method is simple and direct, suitable for rapid iteration and small teams. But as the project develops, a single repository gradually exposes some problems:
1.1 Repository Size Too Large
When the project's code volume reaches a certain scale, the repository size becomes very large, leading to:
- Longer clone and pull times
- Slower IDE loading speeds, affecting development efficiency
- Slow Git operations (like branch switching, merging)
- Difficult code search and navigation
1.2 Team Collaboration Conflicts
In large teams, multiple teams developing simultaneously in one repository leads to:
- Complex branch management, prone to conflicts
- Difficult code reviews, needing to review a lot of unrelated code
- Hard to refine permission management, unable to achieve repository-level access control
- Complex release processes, where a small change can affect the entire project
1.3 Tech Stack Differences
As the business develops, different modules may need to use different tech stacks:
- The main application might use Vue 3
- The mobile side might use React Native
- Utility libraries might use pure TypeScript
- These tech stack differences complicate build processes and dependency management
1.4 Independent Release Requirements
Certain modules may need independent release and version management:
- A UI component library needs to be independently published to npm
- An SDK needs to support multiple parallel versions
- Different business lines may need independent release cycles
It is precisely for these reasons that many teams start to shift towards a multi-repo management model, splitting large projects into multiple independent repositories, each responsible for a specific module or function.
2. Common Challenges of Multi-Repo Management
Although multi-repo management solves some problems of a single repository, it also brings new challenges. Let's look at the problems often encountered in practice.
2.1 Inconsistent Dependency Versions
In a multi-repo model, each repository has its own package.json, which leads to:
Problem Example:
- Repo A uses React 17
- Repo B uses React 18
- Repo C uses React 17.0.2
This version inconsistency brings the following problems:
- Components behave inconsistently across different repositories
- Upgrading dependencies requires updating each repository individually, easy to miss one
- Debugging is difficult because different repositories use different versions of dependencies
Solution:
Use unified dependency version management tools like npm-check-updates, renovate, or dependabot to regularly check and update dependency versions across all repositories.
2.2 Difficulty Sharing Code Across Repositories
In a multi-repo model, code sharing becomes very difficult:
Problem Scenario:
- Repo A has a common utility function
- Repo B also needs to use this function
- Repo C needs it too
There are two traditional solutions:
- Copy-Paste: Copy the code into each repository, but this leads to maintenance difficulties; a change in one place needs to be synchronized in multiple places.
- npm Package: Publish the shared code as an npm package, but this increases the complexity of the release process; every modification requires a re-publish.
Solution: Use a Monorepo architecture, placing all repositories in one large repository and implementing code sharing through a workspace mechanism.
2.3 Time-Consuming Redundant Builds
In a multi-repo model, each repository needs to be built independently, which leads to:
- Lengthy CI/CD processes
- Wasted resources, as each repository needs to install dependencies and build
- Inability to implement incremental builds; rebuilding is needed even if the code hasn't changed
Solution: Use tools that support incremental builds and caching, such as Turborepo, NX, etc.
2.4 Difficult Version Coordination
When dependencies exist between multiple repositories, version coordination becomes very complex:
Scenario Example:
- Repo A depends on v1.0.0 of Repo B
- Repo B updates to v2.0.0, introducing breaking changes
- If Repo A doesn't update in time, compatibility issues will arise
Solution: Establish a clear version dependency graph and use automated tools to track and remind about version updates.
2.5 Complex Development Environment Configuration
Each repository needs its own development environment configured, which leads to:
- New members needing to configure environments for multiple repositories when joining
- Inconsistent environment configurations across repositories, leading to the "it works on my machine" problem
- Environment configuration documentation being difficult to maintain and synchronize
Solution: Use containerization technology (like Docker) to unify the development environment, or use a Monorepo to share configurations.
3. Monorepo vs Multi-repo: How to Choose?
When discussing multi-repo management, we inevitably face the choice between Monorepo and Multi-repo. These two approaches have their own pros and cons, suitable for different scenarios.
3.1 What is Monorepo?
Monorepo (single repository) is a management approach that places multiple projects or modules in the same Git repository. A typical Monorepo structure looks like this:
my-monorepo/
├── packages/
│ ├── app/ # Main application
│ ├── ui/ # UI component library
│ ├── sdk/ # SDK
│ └── utils/ # Utility function library
├── .gitignore
├── package.json
└── README.md
3.2 What is Multi-repo?
Multi-repo (multiple repositories) is a management approach that places each project or module in an independent Git repository. A typical Multi-repo structure looks like this:
my-project/
├── app/ # Independent repo
├── ui/ # Independent repo
├── sdk/ # Independent repo
└── utils/ # Independent repo
3.3 Pros and Cons Comparison
| Comparison Dimension | Monorepo | Multi-repo |
|---|---|---|
| Code Sharing | Convenient, direct reference | Difficult, requires publishing npm package |
| Dependency Management | Unified, consistent versions | Decentralized, prone to version inconsistency |
| Build Efficiency | Supports incremental builds, high efficiency | Redundant builds, low efficiency |
| Team Collaboration | Prone to conflicts | Fewer conflicts |
| Permission Management | Hard to refine | Easy to refine |
| Release Process | Unified release, high complexity | Independent release, simple and flexible |
| Repository Size | Larger | Smaller |
| Tech Stack Isolation | Harder | Easier |
3.4 How to Choose?
Choosing Monorepo or Multi-repo depends on your team and project situation:
Scenarios for Choosing Monorepo:
- Large team size, requiring efficient code sharing
- Tight dependencies between multiple projects
- Need for a unified build process and toolchain
- Pursuit of efficient CI/CD and incremental builds
Scenarios for Choosing Multi-repo:
- Each project is relatively independent with few dependencies
- Need for refined permission management
- Different projects use different tech stacks
- Projects need independent release and version management
Hybrid Model: Many teams adopt a hybrid model, placing related projects in a Monorepo and independent projects in separate repositories. For example:
frontend/ # Monorepo
├── packages/
│ ├── app/
│ ├── ui/
│ └── shared/
backend/ # Independent repo
mobile/ # Independent repo
docs/ # Independent repo
4. Mainstream Multi-Repo Management Tools
With the development of front-end engineering, many excellent multi-repo management tools have emerged. These tools can help us solve various problems in multi-repo management.
4.1 pnpm Workspace
pnpm is a fast, disk-space-saving package manager that provides powerful workspace features for easily managing multiple packages.
Install pnpm:
npm install -g pnpm
Initialize Workspace:
mkdir my-monorepo && cd my-monorepo
pnpm init
Configure workspace:
Create a pnpm-workspace.yaml file in the root directory:
packages:
- 'packages/*'
- 'apps/*'
Create sub-packages:
mkdir -p packages/ui packages/utils apps/web
pnpm init -C packages/ui
pnpm init -C packages/utils
pnpm init -C apps/web
Add dependencies:
# Add dependency for all packages
pnpm add lodash -w
# Add dependency for a specific package
pnpm add react -C apps/web
# Add cross-package dependency
pnpm add @my-monorepo/ui -C apps/web
Run scripts:
# Run the build script for all packages
pnpm run build --filter '*'
# Run a script for a specific package
pnpm run dev --filter @my-monorepo/web
# Run multiple scripts in parallel
pnpm run dev --filter '@my-monorepo/*' --parallel
Pros:
- Fast installation speed, saves disk space
- Simple and intuitive workspace configuration
- Supports cross-package dependencies, can reference without publishing
- Built-in script running and filtering features
Cons:
- Incremental build functionality is relatively simple
- Lacks advanced task orchestration capabilities
4.2 Turborepo
Turborepo is a high-performance Monorepo build tool launched by Vercel, focusing on incremental builds and caching.
Install Turborepo:
# Initialize using the official scaffolding
npx create-turbo@latest
Configure turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["package.json"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false
},
"lint": {
"outputs": []
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
}
}
}
Run tasks:
# Build all packages
npx turbo run build
# Build in parallel
npx turbo run build --parallel
# Only build affected packages
npx turbo run build --filter=@my-monorepo/web...
# Clean cache
npx turbo prune --scope=@my-monorepo/web
Pros:
- Extremely fast incremental builds
- Smart caching mechanism to avoid redundant builds
- Supports remote caching, team shares build results
- Clear task dependency definition
Cons:
- Configuration is relatively complex
- Ecosystem is relatively new, toolchain not rich enough
4.3 NX
NX is a powerful Monorepo development tool that provides a complete development experience.
Install NX:
# Initialize using the official scaffolding
npx create-nx-workspace@latest
Create applications and libraries:
# Create a React application
nx generate @nx/react:app web
# Create a shared library
nx generate @nx/react:lib ui-components
# Create a utility library
nx generate @nx/js:lib utils
Run tasks:
# Build application
nx build web
# Run development server
nx serve web
# Run tests
nx test ui-components
# Only build affected projects
nx affected:build
# Visualize dependency graph
nx graph
Configure project dependencies:
{
"name": "@my-monorepo/web",
"dependencies": {
"@my-monorepo/ui-components": "1.0.0",
"@my-monorepo/utils": "1.0.0"
}
}
Pros:
- Comprehensive features, provides a complete development toolchain
- Powerful code generation capabilities
- Rich plugin ecosystem, supports multiple tech stacks
- Visual dependency graph
Cons:
- Steep learning curve
- Complex configuration, high flexibility
4.4 Lerna
Lerna is a veteran Monorepo management tool, focusing on version management and publishing.
Install Lerna:
npm install -g lerna
Initialize Lerna project:
mkdir my-monorepo && cd my-monorepo
lerna init
Configure lerna.json:
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"version": "0.0.0",
"npmClient": "pnpm",
"useWorkspaces": true,
"packages": ["packages/*"]
}
Manage versions:
# List versions of all packages
lerna ls
# Upgrade versions of all packages
lerna version
# Publish all packages
lerna publish
# Publish a specific package
lerna publish --scope=@my-monorepo/ui
Run scripts:
# Run script in all packages
lerna run build
# Run script in a specific package
lerna run build --scope=@my-monorepo/web
# Run scripts in parallel
lerna run dev --parallel
Pros:
- Powerful version management and publishing features
- Supports both independent and unified version modes
- Mature community, rich documentation
Cons:
- Build performance is relatively poor
- Functionality is relatively singular, mainly focused on version management
4.5 Tool Comparison and Selection
| Tool | Core Advantage | Applicable Scenario |
|---|---|---|
| pnpm Workspace | Simple, lightweight, efficient dependency management | Small to medium projects, quick start |
| Turborepo | Incremental builds, efficient caching | Projects requiring high-performance builds |
| NX | Comprehensive features, complete toolchain | Large enterprise-level projects, complex needs |
| Lerna | Version management, release process | Projects requiring fine-grained version control |
Recommendations:
- If your project is small and pursues simplicity and efficiency, choose pnpm Workspace
- If your project needs high-performance builds and caching, choose Turborepo
- If your project is a large enterprise-level application needing a complete toolchain, choose NX
- If your project mainly focuses on version management and publishing, choose Lerna
Many teams use a combination of these tools, for example: pnpm Workspace + Turborepo or pnpm Workspace + Lerna.
5. Multi-repo Management Strategies and Tools
Although Monorepo is the current mainstream trend, in many scenarios, Multi-repo (true multiple repositories) is still a necessary choice. This section introduces management strategies and tools in Multi-repo mode.
5.1 Git Submodule
Git Submodule is a multi-repo management solution officially provided by Git, allowing one repository to reference another repository as a subdirectory.
Add submodule:
git submodule add https://github.com/user/repo.git packages/ui
Initialize submodules:
# After cloning a repository containing submodules
git submodule init
git submodule update
# Or initialize directly when cloning
git clone --recursive https://github.com/user/main-repo.git
Update submodules:
# Update all submodules to the latest version
git submodule update --remote
# Update a specific submodule
git submodule update --remote packages/ui
Commit submodule changes:
# Commit changes in the submodule
cd packages/ui
git add .
git commit -m "Update UI component"
git push
# Commit the submodule reference update in the main repository
cd ..
git add packages/ui
git commit -m "Update UI submodule"
git push
Pros:
- Native Git support, no extra tools needed
- Submodules can have independent version management
- Suitable for referencing third-party libraries or independently maintained modules
Cons:
- Complex operations, high learning cost
- Cumbersome clone and update steps
- Easy to forget to update submodules
- Complex branch management for submodules
5.2 Git Subtree
Git Subtree is another multi-repo management solution that merges the code of a sub-repository directly into the main repository, rather than as an independent reference.
Add subtree:
git subtree add --prefix=packages/ui https://github.com/user/ui.git main
Update subtree:
git subtree pull --prefix=packages/ui https://github.com/user/ui.git main
Push changes to subtree:
git subtree push --prefix=packages/ui https://github.com/user/ui.git main
Pros:
- Transparent to developers, no special operations needed
- Code is directly in the main repository, easy to view and modify
- Avoids the complex operations of submodule
Cons:
- Main repository size will increase
- Complex branch management and merging
- Pushing changes to the sub-repository requires extra operations
5.3 Rush
Rush is a multi-repo management tool developed by Microsoft, focusing on dependency management and release processes for large projects.
Install Rush:
npm install -g @microsoft/rush
Initialize Rush project:
mkdir my-rush-project && cd my-rush-project
rush init
Configure rush.json:
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush.schema.json",
"pnpmVersion": "9.0.0",
"rushVersion": "6.0.0",
"projects": [
{
"packageName": "@my-project/app",
"projectFolder": "apps/app"
},
{
"packageName": "@my-project/ui",
"projectFolder": "packages/ui"
},
{
"packageName": "@my-project/utils",
"projectFolder": "packages/utils"
}
]
}
Install dependencies:
rush install
Build project:
rush build
Publish packages:
rush publish --apply
Pros:
- Powerful dependency management, supports version policies
- Supports incremental builds and caching
- Provides a unified release process
- Suitable for large enterprise-level projects
Cons:
- Complex configuration, steep learning curve
- Relatively small ecosystem
5.4 Changesets
Changesets is a tool for managing versions and CHANGELOGs, particularly suitable for multi-repo projects.
Install Changesets:
pnpm install -D @changesets/cli
Initialize Changesets:
npx changeset init
Create a changeset:
npx changeset
Execute version update:
npx changeset version
Publish packages:
npx changeset publish
Configuration example:
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": "@changesets/cli/changelog",
"commit": false,
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}
Pros:
- Simple and easy to use, focused on version management
- Automatically generates CHANGELOG
- Supports cross-package version linking
- Suitable for multi-package projects needing independent version management
Cons:
- Functionality is relatively singular, mainly focused on version management
- Needs to be used in conjunction with other build tools
5.5 Cross-Repository CI/CD Orchestration
In Multi-repo mode, cross-repository CI/CD orchestration is an important challenge. Here are some common solutions:
Using GitHub Actions for orchestration:
name: Cross-repo Build
on:
push:
branches: [main]
jobs:
build-ui:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: user/ui
path: ui
- run: cd ui && npm install && npm run build
- uses: actions/upload-artifact@v4
with:
name: ui-build
path: ui/dist
build-app:
runs-on: ubuntu-latest
needs: build-ui
steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: ui-build
path: node_modules/@my-project/ui/dist
- run: npm install && npm run build
Using Jenkins Pipeline:
pipeline {
agent any
stages {
stage('Build UI') {
steps {
git url: 'https://github.com/user/ui.git', branch: 'main'
sh 'npm install && npm run build'
stash includes: 'dist/**', name: 'ui-build'
}
}
stage('Build App') {
steps {
git url: 'https://github.com/user/app.git', branch: 'main'
unstash 'ui-build'
sh 'npm install && npm run build'
}
}
}
}
5.6 Multi-Repo Coordination Tools
Besides the tools mentioned above, there are some tools specifically for multi-repo coordination:
Repo Manager: A custom multi-repo management tool supporting batch operations, status monitoring, task orchestration, and more. Refer to the design document multi-repo-manager-design.md for detailed design.
Key Features:
- Batch clone, pull, push code
- Unified dependency management and version synchronization
- Real-time status monitoring and alert notifications
- Task orchestration and automated workflows
gh repo sync: GitHub CLI's repository sync command, supports cross-repository synchronization of branches and tags.
# Sync branch
git repo sync user/repo --source user/source-repo --branch main
# Sync all branches
git repo sync user/repo --source user/source-repo --all
6. Hands-On: Building a Complete Multi-Repo Project
Now, let's demonstrate how to build a complete multi-repo project through a practical case. We will use the combination of pnpm Workspace + Turborepo.
6.1 Project Structure Design
First, we need to design a reasonable project structure. A typical multi-repo project structure looks like this:
my-monorepo/
├── apps/ # Application layer
│ ├── web/ # Web main application
│ └── mobile/ # Mobile application
├── packages/ # Package layer
│ ├── ui/ # UI component library
│ ├── sdk/ # SDK
│ ├── utils/ # Utility function library
│ └── hooks/ # Custom Hooks
├── .gitignore
├── package.json
├── pnpm-workspace.yaml
├── turbo.json
└── README.md
Design Principles:
- Clear Hierarchy: Separate application layer and package layer for easier management
- Single Responsibility: Each package is responsible for only one functional domain
- Modularity: Packages should remain as independent as possible, reducing coupling
6.2 Initialize Project
Step 1: Create project directory
mkdir my-monorepo && cd my-monorepo
Step 2: Initialize pnpm
pnpm init -y
Step 3: Create workspace configuration
cat > pnpm-workspace.yaml << EOF
packages:
- 'apps/*'
- 'packages/*'
EOF
Step 4: Initialize Turborepo
npx turbo init -y
Step 5: Create directory structure
mkdir -p apps/web apps/mobile
mkdir -p packages/ui packages/sdk packages/utils packages/hooks
6.3 Configure Basic Tools
Configure tsconfig.json:
Create tsconfig.json in the root directory to share TypeScript configuration:
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"moduleResolution": "bundler",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",
"baseUrl": ".",
"paths": {
"@my-monorepo/ui": ["packages/ui/src/index.ts"],
"@my-monorepo/sdk": ["packages/sdk/src/index.ts"],
"@my-monorepo/utils": ["packages/utils/src/index.ts"],
"@my-monorepo/hooks": ["packages/hooks/src/index.ts"]
}
},
"include": ["apps/**/*", "packages/**/*"],
"exclude": ["node_modules"]
}
Configure turbo.json:
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["package.json"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"dev": {
"cache": false
},
"lint": {
"outputs": []
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
}
}
}
6.4 Create Packages and Applications
Create UI Component Library:
cd packages/ui
pnpm init -y
pnpm add react react-dom @types/react @types/react-dom
Create packages/ui/src/Button.tsx:
import React from 'react';
interface ButtonProps {
children: React.ReactNode;
onClick?: () => void;
variant?: 'primary' | 'secondary' | 'danger';
}
export const Button = ({ children, onClick, variant = 'primary' }: ButtonProps) => {
const styles = {
primary: {
backgroundColor: '#3e95cd',
color: 'white',
},
secondary: {
backgroundColor: '#e0e0e0',
color: '#333',
},
danger: {
backgroundColor: '#e74c3c',
color: 'white',
},
};
return (
<button
onClick={onClick}
style={{
...styles[variant],
padding: '8px 16px',
border: 'none',
borderRadius: '4px',
cursor: 'pointer',
fontSize: '14px',
}}
>
{children}
</button>
);
};
Create packages/ui/src/index.ts:
export { Button } from './Button';
Create Utility Function Library:
cd ../utils
pnpm init -y
Create packages/utils/src/format.ts:
export const formatDate = (date: Date): string => {
return date.toLocaleDateString('zh-CN', {
year: 'numeric',
month: '2-digit',
day: '2-digit',
});
};
export const formatNumber = (num: number): string => {
return num.toLocaleString('zh-CN');
};
Create packages/utils/src/index.ts:
export { formatDate, formatNumber } from './format';
Create Web Application:
cd ../../apps/web
pnpm init -y
pnpm add react react-dom @types/react @types/react-dom
pnpm add @my-monorepo/ui @my-monorepo/utils
pnpm add -D vite @vitejs/plugin-react typescript
Create apps/web/vite.config.ts:
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@my-monorepo/ui': '../../packages/ui/src',
'@my-monorepo/utils': '../../packages/utils/src',
},
},
});
Create apps/web/src/App.tsx:
import { Button } from '@my-monorepo/ui';
import { formatDate, formatNumber } from '@my-monorepo/utils';
function App() {
const handleClick = () => {
console.log('Button clicked!');
};
return (
<div style={{ padding: '20px' }}>
<h1>Welcome to My Monorepo</h1>
<p>Today is: {formatDate(new Date())}</p>
<p>Number: {formatNumber(1234567)}</p>
<div style={{ marginTop: '20px' }}>
<Button onClick={handleClick}>Primary Button</Button>
<Button variant="secondary" style={{ marginLeft: '10px' }}>
Secondary Button
</Button>
<Button variant="danger" style={{ marginLeft: '10px' }}>
Danger Button
</Button>
</div>
</div>
);
}
export default App;
6.5 Add Script Commands
Add scripts in the root package.json:
{
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev --parallel",
"lint": "turbo run lint",
"test": "turbo run test",
"clean": "turbo run clean && rm -rf node_modules",
"format": "prettier --write \"**/*.{ts,tsx,js,jsx,json}\""
}
}
Add scripts in the package.json of each package and application:
packages/ui/package.json:
{
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint ."
}
}
packages/utils/package.json:
{
"scripts": {
"build": "tsc",
"dev": "tsc --watch",
"lint": "eslint ."
}
}
apps/web/package.json:
{
"scripts": {
"build": "vite build",
"dev": "vite",
"lint": "eslint ."
}
}
6.6 Run Project
Build all packages:
pnpm build
Start development server:
pnpm dev
Only build affected packages:
pnpm build --filter=@my-monorepo/web...
7. Best Practices for Multi-Repo Management
In real projects, to do multi-repo management well, besides choosing the right tools, you also need to follow some best practices.
7.1 Maintain a Clear Directory Structure
A clear directory structure is the foundation of multi-repo management. It is recommended to organize according to the following principles:
my-monorepo/
├── apps/ # Application layer, stores independently runnable applications
│ ├── web/ # Web application
│ ├── mobile/ # Mobile application
│ └── admin/ # Admin dashboard
├── packages/ # Package layer, stores shareable code
│ ├── ui/ # UI component library
│ ├── sdk/ # SDK
│ ├── utils/ # Utility function library
│ ├── hooks/ # Custom Hooks
│ └── config/ # Shared configuration
├── scripts/ # Scripts directory, stores automation scripts
├── docs/ # Documentation directory
└── tools/ # Tools directory, stores development tools
7.2 Unify Dependency Versions
In a multi-repo, unifying dependency versions is very important. This can be achieved through the following methods:
Use pnpm's workspace protocol:
pnpm add react -w
Use a unified version configuration file:
Create a .versionrc.json or versions.json file to centrally manage dependency versions:
{
"react": "^18.2.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
Use automation tools:
Configure renovate or dependabot to regularly check and update dependency versions.
7.3 Establish Clear Dependency Relationships
In a multi-repo, dependency relationships between packages should be clear and explicit. This can be managed through the following methods:
Use TypeScript path aliases:
{
"compilerOptions": {
"paths": {
"@my-monorepo/ui": ["packages/ui/src"],
"@my-monorepo/utils": ["packages/utils/src"]
}
}
}
Avoid circular dependencies: Circular dependencies can cause build failures and runtime errors and must be strictly avoided. The following tools can be used for detection:
madge: Visualize dependency relationshipstsc --listFiles: View file dependencies
Control dependency depth: Minimize the depth of dependencies between packages, recommended not to exceed 3 levels.
7.4 Implement Incremental Builds
Incremental builds are key to improving multi-repo build efficiency. This can be achieved through the following methods:
Use Turborepo or NX: These tools have powerful built-in incremental build and caching mechanisms.
Configure build output caching:
Configure output directories in turbo.json:
{
"pipeline": {
"build": {
"outputs": ["dist/**"]
}
}
}
Use remote caching: Configure remote caching for Turborepo or NX so team members can share build results.
7.5 Standardize Code Conventions
In a multi-repo, maintaining consistency in code conventions is very important. This can be achieved through the following methods:
Share ESLint configuration:
Create a packages/eslint-config package to share ESLint configuration.
Share Prettier configuration:
Create a .prettierrc file in the root directory to unify formatting rules.
Use Git Hooks:
Configure husky and lint-staged to automatically check and format code before committing.
7.6 Establish Automated Workflows
Automated workflows can greatly improve the team's development efficiency. It is recommended to configure the following automation processes:
CI/CD Process:
- Automatically run lint and test after code submission
- Automatically build and deploy after merging to the main branch
- Use incremental builds to reduce CI time
Version Management:
- Use Conventional Commits specification
- Use
standard-versionorchangesetsto automatically generate version numbers and CHANGELOG
Dependency Updates:
- Use
renovateto automatically update dependencies - Use
pnpm auditto regularly check for security vulnerabilities
7.7 Documentation and Knowledge Sharing
In a multi-repo, documentation and knowledge sharing are particularly important. It is recommended to:
Write README files: Each package and application should have a clear README file explaining:
- The package's functionality and purpose
- Installation and usage methods
- API documentation
- Example code
Create architecture documentation: Write architecture documentation explaining:
- Project structure and design principles
- Dependency relationships between packages
- Build and deployment processes
- Development conventions and best practices
Regular sharing and training: Organize team sharing sessions to introduce project structure and best practices, helping new members get up to speed quickly.
8. Common Problems and Solutions
In the practice of multi-repo management, you may encounter some common problems. Let's look at how to solve these problems.
8.1 Circular Dependencies Between Packages
Problem: Package A depends on Package B, and Package B depends on Package A, forming a circular dependency.
Solution:
- Refactor Code: Extract common code into an independent package
- Use Type Imports: Only import types to avoid runtime dependencies
- Use Event Mechanism: Decouple dependencies between packages through an event bus
Example:
// Package A
import type { Data } from '@my-monorepo/b';
export const processData = (data: Data): void => {
// Process data
};
8.2 Build Cache Invalidation
Problem: Turborepo or NX's cache is not working correctly, causing a full rebuild every time.
Solution:
- Check Output Directory Configuration: Ensure
outputsis correctly configured inturbo.json - Check Global Dependencies: Ensure
globalDependenciesincludes all files that affect the build - Clean Cache: Run
npx turbo pruneto clean the cache and rebuild - Check Environment Variables: Ensure the cache is correctly configured in the CI environment
8.3 Dependency Version Conflicts
Problem: Different packages use different versions of the same dependency, causing build or runtime errors.
Solution:
- Use Workspace Protocol: Install dependencies in the root directory to ensure version consistency
- Use resolutions: Force specify dependency versions in
package.json - Use overrides: Override dependency versions in
pnpm.overrides
Example:
{
"pnpm": {
"overrides": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}
}
8.4 CI/CD Process Too Slow
Problem: The CI/CD process for a multi-repo takes too long, affecting development efficiency.
Solution:
- Use Incremental Builds: Configure incremental builds for Turborepo or NX
- Use Remote Caching: Configure remote caching in CI
- Run Tasks in Parallel: Use the
--paralleloption to run tasks in parallel - Only Build Affected Packages: Use the
--filteroption to only build affected packages
8.5 Difficult Onboarding for New Members
Problem: After new members join, they need to spend a lot of time understanding the project structure and configuration.
Solution:
- Write Detailed Documentation: Including project structure, development process, tool usage, etc.
- Create Onboarding Guide: Provide a step-by-step getting started tutorial
- Configure a Unified Development Environment: Use Docker or scripts to configure the environment with one click
- Organize Pair Programming: Arrange for experienced members to pair with new members to help them get up to speed quickly
9. Summary and Outlook
Front-end multi-repo management is a complex but important topic. As project scale expands and teams grow, choosing the right repository management method becomes increasingly critical.
In this article, we introduced:
- The necessity and challenges of multi-repo management
- The pros and cons of Monorepo and Multi-repo, and the basis for choosing
- Mainstream Monorepo management tools (pnpm Workspace, Turborepo, NX, Lerna)
- Multi-repo management strategies and tools (Git Submodule, Git Subtree, Rush, Changesets)
- Cross-repository CI/CD orchestration solutions
- Practical case: Building a project using pnpm Workspace + Turborepo
- Best practices for multi-repo management
- Common problems and solutions
In the future, with the continuous development of front-end engineering, we may see more intelligent multi-repo management tools emerge. These tools will further simplify the repository management process and improve development efficiency.
Regardless of which management method you choose, the core principles are: maintain a clear structure, unified conventions, an efficient toolchain, and automated workflows. Only in this way can multi-repo management move from chaos to order, allowing the team to focus on business development rather than tedious repository management tasks.
I hope this article helps you better understand and practice front-end multi-repo management. Good luck with your projects!
📱 Practical Tool Recommendation
In daily work and life, we often need to handle various video resources. If you need to download videos from short video platforms but are troubled by annoying watermarks, this mini-program is definitely worth a try!
Sanxia Video Watermark Remover
Features:
- 🎬 One-Click Watermark Removal: Supports mainstream short video platforms like Douyin, Kuaishou, Xiaohongshu, Bilibili, etc. Copy the share link to automatically extract the watermark-free video
- 🚀 High-Speed Download: Intelligently parses video links, obtaining high-definition watermark-free videos in seconds
- 💾 Local Saving: Downloaded videos are saved directly to the phone's photo album, convenient for viewing anytime and using as material or sharing
- 🆓 Completely Free: All features are permanently free to use, no unlock ads interference, no hidden charges
How to Use:
- Find a video you like on the short video platform, click the share button
- Copy the video's share link
- Open the "Sanxia Video Watermark Remover" mini-program
- Paste the link, click parse, and you can get and download the watermark-free video
Search Method:
Search for "Sanxia Video Watermark Remover" in the WeChat mini-programs to find and use this practical tool!
Whether you need to extract video material for work or want to save your favorite short videos in life, "Sanxia Video Watermark Remover" can help you get it done easily, making watermark removal and downloading simple and efficient!