正在加载,请稍候…

Monorepo Strategy: Turborepo, Nx, Remote Caching, and Package Architecture

Design scalable monorepos with Turborepo and Nx. Remote caching, task orchestration, shared package architecture, code generation, and CI optimization for large JavaScript codebases.

Monorepos enable code sharing, consistent tooling, and atomic commits across packages. Here's how to set one up that scales.

Turborepo Setup

// package.json
{
  "name": "my-monorepo",
  "private": true,
  "workspaces": ["apps/*", "packages/*"],
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev --parallel",
    "test": "turbo run test",
    "lint": "turbo run lint"
  },
  "devDependencies": { "turbo": "^2.0.0" }
}
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "remoteCache": { "enabled": true },
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["src/**", "package.json", "tsconfig.json"],
      "outputs": ["dist/**", ".next/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "cache": true
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

Package Architecture

apps/
  ├── web/          # Next.js
  ├── mobile/       # React Native
  └── api/          # Node.js
packages/
  ├── ui/           # Shared components
  ├── utils/        # Shared utilities
  ├── types/        # Shared TypeScript types
  └── config/       # Shared ESLint/TS configs
// packages/ui/package.json
{
  "name": "@company/ui",
  "main": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts",
    "./button": "./src/components/button/index.ts"
  },
  "scripts": {
    "build": "tsup src/index.ts --format esm,cjs --dts"
  },
  "peerDependencies": { "react": ">=18" }
}

Shared TypeScript Config

// packages/config/tsconfig-base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "exactOptionalPropertyTypes": true,
    "verbatimModuleSyntax": true
  }
}
// apps/web/tsconfig.json
{
  "extends": "@company/config/tsconfig-base.json",
  "compilerOptions": {
    "lib": ["ES2022", "DOM"],
    "module": "ESNext",
    "jsx": "react-jsx"
  }
}

CI with Remote Cache

# .github/workflows/ci.yml
jobs:
  build-and-test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with: { node-version: 20, cache: npm }
      - run: npm ci
      - run: turbo run build test lint
        env:
          TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
          TURBO_TEAM: ${{ vars.TURBO_TEAM }}
          # Remote cache: unchanged packages take 0ms
          # Typical: 20min CI → 2min with cache hits

Nx for Very Large Repos

# Affected commands: only process changed packages
nx affected --target=build --base=origin/main
nx affected --target=test --base=HEAD~1

# Generate library
nx generate @nx/react:library --name=feature-auth

# Dependency graph visualization
nx graph

The monorepo investment pays off the moment your second app needs code from the first. Design boundaries around feature domains, not technical layers.

→ Analyze your package.json dependencies with the JSON Viewer tool.