10. Monorepo Management

10. Monorepo Management

Learning Objectives

  • Understand monorepo concepts and pros/cons
  • Build optimization with Nx and Turborepo
  • Dependency management and code sharing strategies
  • Performance optimization for large-scale monorepos

Table of Contents

  1. Monorepo Overview
  2. Monorepo Tools
  3. Using Nx
  4. Using Turborepo
  5. Dependency Management
  6. CI/CD Optimization
  7. Practice Exercises

1. Monorepo Overview

1.1 Monorepo vs Polyrepo

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Polyrepo (Polyrepo)                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”            β”‚
β”‚  β”‚ frontend   β”‚  β”‚ backend    β”‚  β”‚ shared-lib β”‚            β”‚
β”‚  β”‚ (repo)     β”‚  β”‚ (repo)     β”‚  β”‚ (repo)     β”‚            β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€            β”‚
β”‚  β”‚ .git/      β”‚  β”‚ .git/      β”‚  β”‚ .git/      β”‚            β”‚
β”‚  β”‚ package.jsonβ”‚ β”‚ package.jsonβ”‚ β”‚ package.jsonβ”‚            β”‚
β”‚  β”‚ src/       β”‚  β”‚ src/       β”‚  β”‚ src/       β”‚            β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜            β”‚
β”‚                                                             β”‚
β”‚  Features:                                                  β”‚
β”‚  β€’ Independent version control                              β”‚
β”‚  β€’ Share packages via npm/pypi                              β”‚
β”‚  β€’ Easy per-project permission management                   β”‚
β”‚  β€’ Risk of dependency version mismatches                    β”‚
β”‚                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚               Monorepo (Monorepo)                            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                                                             β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚  β”‚ my-company (single repo)                              β”‚ β”‚
β”‚  β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚
β”‚  β”‚ .git/                                                 β”‚ β”‚
β”‚  β”‚ package.json (root)                                   β”‚ β”‚
β”‚  β”‚ nx.json / turbo.json                                  β”‚ β”‚
β”‚  β”‚                                                       β”‚ β”‚
β”‚  β”‚ packages/                                             β”‚ β”‚
β”‚  β”‚   β”œβ”€β”€ frontend/                                       β”‚ β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ package.json                               β”‚ β”‚
β”‚  β”‚   β”‚   └── src/                                       β”‚ β”‚
β”‚  β”‚   β”œβ”€β”€ backend/                                        β”‚ β”‚
β”‚  β”‚   β”‚   β”œβ”€β”€ package.json                               β”‚ β”‚
β”‚  β”‚   β”‚   └── src/                                       β”‚ β”‚
β”‚  β”‚   └── shared-lib/                                     β”‚ β”‚
β”‚  β”‚       β”œβ”€β”€ package.json                               β”‚ β”‚
β”‚  β”‚       └── src/                                       β”‚ β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚                                                             β”‚
β”‚  Features:                                                  β”‚
β”‚  β€’ All code in single repository                            β”‚
β”‚  β€’ Atomic commits (modify multiple packages at once)       β”‚
β”‚  β€’ Easy code reuse                                          β”‚
β”‚  β€’ Consistent tools and settings                            β”‚
β”‚                                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1.2 Monorepo Pros and Cons

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                          Pros                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ βœ“ Easy code sharing                                             β”‚
β”‚   - Shared libraries immediately available                      β”‚
β”‚   - No version mismatch issues                                  β”‚
β”‚                                                                β”‚
β”‚ βœ“ Atomic changes                                                β”‚
β”‚   - Changes across multiple packages in single commit          β”‚
β”‚   - API changes and client updates simultaneously              β”‚
β”‚                                                                β”‚
β”‚ βœ“ Consistency                                                   β”‚
β”‚   - Same lint, test, build configuration                        β”‚
β”‚   - Same dependency versions                                    β”‚
β”‚                                                                β”‚
β”‚ βœ“ Easy refactoring                                              β”‚
β”‚   - Search/modify across entire codebase                        β”‚
β”‚   - IDE support (autocomplete, find references)                 β”‚
β”‚                                                                β”‚
β”‚ βœ“ Team collaboration                                            β”‚
β”‚   - Easy reference to other teams' code                         β”‚
β”‚   - Understand full context in code reviews                     β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚                          Cons                                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ βœ— Repository size                                               β”‚
β”‚   - Increased clone time                                        β”‚
β”‚   - Complex CI caching                                          β”‚
β”‚                                                                β”‚
β”‚ βœ— Build time                                                    β”‚
β”‚   - Full builds take long                                       β”‚
β”‚   - Optimization needed to build only affected parts            β”‚
β”‚                                                                β”‚
β”‚ βœ— Tool complexity                                               β”‚
β”‚   - Dedicated tools needed (Nx, Turborepo, Bazel)             β”‚
β”‚   - Learning curve                                              β”‚
β”‚                                                                β”‚
β”‚ βœ— Permission management                                         β”‚
β”‚   - Difficult per-code access control                           β”‚
β”‚   - Partially solved with CODEOWNERS                            β”‚
β”‚                                                                β”‚
β”‚ βœ— Dependency conflicts                                          β”‚
β”‚   - Issues when different versions needed                       β”‚
β”‚   - Hoisting issues                                             β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

1.3 Monorepo Use Cases

Major monorepo examples:
β€’ Google - billions of lines of code, single repository
β€’ Facebook - React, Jest, etc.
β€’ Microsoft - managed with Rush.js
β€’ Uber - Go monorepo
β€’ Airbnb - JavaScript monorepo

Good fit for:
β€’ Multiple apps sharing common code
β€’ Microservices + shared libraries
β€’ Same team managing multiple packages
β€’ API and client need synchronization

Not suitable for:
β€’ Completely independent projects
β€’ Different languages/tech stacks
β€’ Strict access control needed
β€’ Open source with many external contributors

2. Monorepo Tools

2.1 Tool Comparison

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      Monorepo Tool Comparison                   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              β”‚     Nx       β”‚  Turborepo   β”‚     Lerna        β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Developer    β”‚    Nrwl      β”‚    Vercel    β”‚   (maintenance)  β”‚
β”‚ Language     β”‚ JS/TS (+more)β”‚    JS/TS     β”‚     JS/TS        β”‚
β”‚ Build cachingβ”‚     βœ“        β”‚      βœ“       β”‚       βœ—          β”‚
β”‚ Remote cache β”‚   Nx Cloud   β”‚Vercel/custom β”‚       βœ—          β”‚
β”‚ Dep graph    β”‚     βœ“        β”‚      βœ“       β”‚       β–³          β”‚
β”‚ Code gen     β”‚     βœ“        β”‚      βœ—       β”‚       βœ—          β”‚
β”‚ Plugins      β”‚    Many      β”‚     Few      β”‚     Few          β”‚
β”‚ Config       β”‚    High      β”‚     Low      β”‚     Low          β”‚
β”‚ Scale fitnessβ”‚  Excellent   β”‚     Good     β”‚   Moderate       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2.2 Basic Structure (npm/yarn/pnpm workspaces)

// package.json (root)
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "scripts": {
    "build": "npm run build --workspaces",
    "test": "npm run test --workspaces",
    "lint": "npm run lint --workspaces"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "eslint": "^8.0.0"
  }
}
# pnpm-workspace.yaml
packages:
  - 'packages/*'
  - 'apps/*'
my-monorepo/
β”œβ”€β”€ package.json
β”œβ”€β”€ pnpm-workspace.yaml
β”œβ”€β”€ packages/
β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   β”œβ”€β”€ package.json
β”‚   β”‚   └── src/
β”‚   └── utils/
β”‚       β”œβ”€β”€ package.json
β”‚       └── src/
└── apps/
    β”œβ”€β”€ web/
    β”‚   β”œβ”€β”€ package.json
    β”‚   └── src/
    └── api/
        β”œβ”€β”€ package.json
        └── src/

3. Using Nx

3.1 Creating Nx Project

# Create new Nx workspace
npx create-nx-workspace@latest my-workspace

# Option selection:
# - Integrated monorepo (integrated)
# - Package-based monorepo (package-based)
# - Standalone app (standalone)

# Add Nx to existing repository
npx nx@latest init

3.2 Nx Structure

my-workspace/
β”œβ”€β”€ nx.json                 # Nx configuration
β”œβ”€β”€ workspace.json          # (optional) Project configuration
β”œβ”€β”€ package.json
β”œβ”€β”€ tsconfig.base.json      # Shared TypeScript config
β”œβ”€β”€ apps/                   # Applications
β”‚   β”œβ”€β”€ web/
β”‚   β”‚   β”œβ”€β”€ project.json    # Per-project config
β”‚   β”‚   β”œβ”€β”€ src/
β”‚   β”‚   └── tsconfig.json
β”‚   └── api/
β”‚       β”œβ”€β”€ project.json
β”‚       β”œβ”€β”€ src/
β”‚       └── tsconfig.json
β”œβ”€β”€ libs/                   # Libraries
β”‚   β”œβ”€β”€ shared/
β”‚   β”‚   β”œβ”€β”€ ui/
β”‚   β”‚   β”‚   β”œβ”€β”€ project.json
β”‚   β”‚   β”‚   └── src/
β”‚   β”‚   └── utils/
β”‚   β”‚       β”œβ”€β”€ project.json
β”‚   β”‚       └── src/
β”‚   └── feature/
β”‚       └── auth/
β”‚           β”œβ”€β”€ project.json
β”‚           └── src/
└── tools/                  # Custom tools

3.3 nx.json Configuration

// nx.json
{
  "$schema": "./node_modules/nx/schemas/nx-schema.json",
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"],
      "cache": true
    },
    "test": {
      "inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
      "cache": true
    },
    "lint": {
      "inputs": ["default", "{workspaceRoot}/.eslintrc.json"],
      "cache": true
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": [
      "default",
      "!{projectRoot}/**/*.spec.ts",
      "!{projectRoot}/tsconfig.spec.json",
      "!{projectRoot}/jest.config.ts"
    ],
    "sharedGlobals": ["{workspaceRoot}/tsconfig.base.json"]
  },
  "plugins": [
    {
      "plugin": "@nx/vite/plugin",
      "options": {
        "buildTargetName": "build",
        "serveTargetName": "serve"
      }
    }
  ],
  "defaultBase": "main"
}

3.4 Nx Commands

# Visualize project graph
nx graph

# Build specific project
nx build web

# Build only affected projects
nx affected:build --base=main

# Test affected projects
nx affected:test --base=main

# Parallel execution
nx run-many --target=build --parallel=5

# Run all projects
nx run-many --target=build --all

# Specific projects only
nx run-many --target=test --projects=web,api

# Check cache status
nx show project web

# Code generation
nx generate @nx/react:component button --project=ui
nx generate @nx/node:application api
nx generate @nx/js:library utils

# Migration
nx migrate latest
nx migrate --run-migrations

3.5 Nx Cloud (Remote Caching)

# Connect to Nx Cloud
npx nx connect-to-nx-cloud

# Or configure manually
# Add to nx.json:
{
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx-cloud",
      "options": {
        "accessToken": "your-access-token",
        "cacheableOperations": ["build", "test", "lint"]
      }
    }
  }
}

4. Using Turborepo

4.1 Turborepo Setup

# Create new project
npx create-turbo@latest

# Add to existing monorepo
npm install turbo --save-dev

4.2 turbo.json Configuration

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"]
    },
    "lint": {
      "outputs": []
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "deploy": {
      "dependsOn": ["build", "test", "lint"]
    }
  }
}

4.3 Turborepo Commands

# Build all packages
turbo build

# Specific package only
turbo build --filter=web

# Include dependencies
turbo build --filter=web...

# Include dependents
turbo build --filter=...shared-ui

# Changed packages only
turbo build --filter=[HEAD^1]

# Limit parallel execution
turbo build --concurrency=10

# Visualize graph
turbo build --graph

# Run without cache
turbo build --force

# Dry run
turbo build --dry-run

4.4 Remote Caching (Vercel)

# Connect to Vercel
npx turbo login
npx turbo link

# Or use environment variables
TURBO_TOKEN=your-token
TURBO_TEAM=your-team
// Add to turbo.json
{
  "remoteCache": {
    "signature": true
  }
}

4.5 Turborepo Project Structure

my-turborepo/
β”œβ”€β”€ turbo.json
β”œβ”€β”€ package.json
β”œβ”€β”€ apps/
β”‚   β”œβ”€β”€ web/
β”‚   β”‚   β”œβ”€β”€ package.json
β”‚   β”‚   β”œβ”€β”€ next.config.js
β”‚   β”‚   └── src/
β”‚   └── docs/
β”‚       β”œβ”€β”€ package.json
β”‚       └── src/
└── packages/
    β”œβ”€β”€ ui/
    β”‚   β”œβ”€β”€ package.json
    β”‚   └── src/
    β”œβ”€β”€ config/
    β”‚   β”œβ”€β”€ eslint/
    β”‚   β”‚   └── package.json
    β”‚   └── typescript/
    β”‚       └── package.json
    └── utils/
        β”œβ”€β”€ package.json
        └── src/

5. Dependency Management

5.1 Internal Package References

// packages/ui/package.json
{
  "name": "@myorg/ui",
  "version": "0.0.0",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./button": {
      "import": "./dist/button.mjs",
      "require": "./dist/button.js"
    }
  },
  "scripts": {
    "build": "tsup src/index.ts --format esm,cjs --dts"
  }
}

// apps/web/package.json
{
  "name": "web",
  "dependencies": {
    "@myorg/ui": "workspace:*",
    "@myorg/utils": "workspace:*"
  }
}

5.2 TypeScript Path Configuration

// tsconfig.base.json (root)
{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@myorg/ui": ["packages/ui/src/index.ts"],
      "@myorg/ui/*": ["packages/ui/src/*"],
      "@myorg/utils": ["packages/utils/src/index.ts"],
      "@myorg/utils/*": ["packages/utils/src/*"]
    }
  }
}

// apps/web/tsconfig.json
{
  "extends": "../../tsconfig.base.json",
  "compilerOptions": {
    "rootDir": "src",
    "outDir": "dist"
  },
  "include": ["src"],
  "references": [
    { "path": "../../packages/ui" },
    { "path": "../../packages/utils" }
  ]
}

5.3 Version Management

# Use Changesets (version management)
npm install @changesets/cli -D
npx changeset init

# Add changeset
npx changeset
# Select version bump type: major/minor/patch
# Select affected packages
# Write change description

# Update versions
npx changeset version

# Publish
npx changeset publish
// .changeset/config.json
{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [["@myorg/ui", "@myorg/utils"]],
  "access": "restricted",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": []
}

5.4 Shared Configuration

// packages/config/eslint/index.js
module.exports = {
  extends: [
    'eslint:recommended',
    'plugin:@typescript-eslint/recommended',
    'prettier'
  ],
  parser: '@typescript-eslint/parser',
  plugins: ['@typescript-eslint'],
  rules: {
    // Common rules
  }
};

// apps/web/.eslintrc.js
module.exports = {
  root: true,
  extends: ['@myorg/eslint-config'],
  // Additional project-specific settings
};

6. CI/CD Optimization

6.1 GitHub Actions Configuration

# .github/workflows/ci.yaml
name: CI

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0  # Full history (needed for affected calculation)

    - uses: pnpm/action-setup@v2
      with:
        version: 8

    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'pnpm'

    - name: Install dependencies
      run: pnpm install --frozen-lockfile

    # When using Nx
    - name: Nx affected
      run: |
        npx nx affected:lint --base=origin/main
        npx nx affected:test --base=origin/main
        npx nx affected:build --base=origin/main

    # When using Turborepo
    # - name: Turbo build
    #   run: pnpm turbo build --filter=[origin/main...]

  # Remote caching (Nx Cloud)
  nx-cloud:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0

    - uses: pnpm/action-setup@v2
    - uses: actions/setup-node@v4
      with:
        node-version: '20'
        cache: 'pnpm'

    - run: pnpm install --frozen-lockfile

    - name: Build with Nx Cloud
      run: npx nx affected:build --base=origin/main
      env:
        NX_CLOUD_ACCESS_TOKEN: ${{ secrets.NX_CLOUD_ACCESS_TOKEN }}

6.2 Affected Scope Analysis

# Nx - list affected projects
nx show projects --affected --base=main

# Affected files list
nx show projects --affected --base=main --files

# Turborepo - changed packages only
turbo build --filter=[HEAD^1]

# Check changed files with Git
git diff --name-only HEAD^1

# Path-based filtering (GitHub Actions)
- uses: dorny/paths-filter@v2
  id: changes
  with:
    filters: |
      web:
        - 'apps/web/**'
      api:
        - 'apps/api/**'
      shared:
        - 'packages/**'

- if: steps.changes.outputs.web == 'true'
  run: pnpm build --filter=web

6.3 Caching Strategy

# GitHub Actions caching
- name: Cache turbo build
  uses: actions/cache@v4
  with:
    path: .turbo
    key: ${{ runner.os }}-turbo-${{ github.sha }}
    restore-keys: |
      ${{ runner.os }}-turbo-

- name: Cache node_modules
  uses: actions/cache@v4
  with:
    path: |
      node_modules
      */*/node_modules
    key: ${{ runner.os }}-modules-${{ hashFiles('**/pnpm-lock.yaml') }}

6.4 Selective Deployment

# Deploy only changed apps
name: Deploy

on:
  push:
    branches: [main]

jobs:
  changes:
    runs-on: ubuntu-latest
    outputs:
      web: ${{ steps.filter.outputs.web }}
      api: ${{ steps.filter.outputs.api }}
    steps:
    - uses: actions/checkout@v4
    - uses: dorny/paths-filter@v2
      id: filter
      with:
        filters: |
          web:
            - 'apps/web/**'
            - 'packages/**'
          api:
            - 'apps/api/**'
            - 'packages/**'

  deploy-web:
    needs: changes
    if: needs.changes.outputs.web == 'true'
    runs-on: ubuntu-latest
    steps:
    - run: echo "Deploying web..."

  deploy-api:
    needs: changes
    if: needs.changes.outputs.api == 'true'
    runs-on: ubuntu-latest
    steps:
    - run: echo "Deploying api..."

7. Practice Exercises

Exercise 1: Initial Monorepo Setup

# Requirements:
# 1. Set up monorepo with pnpm workspaces
# 2. Create shared UI library
# 3. Use UI library in web app
# 4. Configure TypeScript paths

# Write structure and configuration files:

Exercise 2: Nx Workspace

# Requirements:
# 1. Create Nx workspace
# 2. Add React app
# 3. Add Node API
# 4. Create shared library
# 5. Check dependency graph

# Write commands:

Exercise 3: Turborepo Pipeline

// Requirements:
// 1. Define build, test, lint, deploy tasks
// 2. Configure appropriate dependencies
// 3. Configure caching
// 4. Configure dev server

// Write turbo.json:

Exercise 4: CI/CD Optimization

# Requirements:
# 1. Build/test only affected projects
# 2. Configure remote caching
# 3. Deploy only changed apps
# 4. Reduce build time with caching

# Write GitHub Actions workflow:

Next Steps

References


← Previous: Advanced Git Techniques | Table of Contents

to navigate between lessons