home / skills / aj-geddes / useful-ai-prompts / monorepo-management

monorepo-management skill

/skills/monorepo-management

This skill helps manage monorepo configurations with Lerna, Turborepo, and Nx to optimize workspace efficiency and cross-package testing.

npx playbooks add skill aj-geddes/useful-ai-prompts --skill monorepo-management

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
7.3 KB
---
name: monorepo-management
description: Manage monorepo architectures using Lerna, Turborepo, and Nx. Configure workspaces, dependency versioning, and cross-package testing.
---

# Monorepo Management

## Overview

Establish scalable monorepo structures that support multiple interdependent packages while maintaining build efficiency, dependency management, and deployment coordination.

## When to Use

- Multi-package projects
- Shared libraries across services
- Microservices architecture
- Plugin-based systems
- Multi-app platforms (web + mobile)
- Workspace dependency management
- Scaled team development

## Implementation Examples

### 1. **Npm Workspaces Configuration**

```json
{
  "name": "monorepo-root",
  "version": "1.0.0",
  "private": true,
  "workspaces": [
    "packages/*",
    "apps/*"
  ],
  "devDependencies": {
    "lerna": "^7.0.0",
    "turbo": "^1.10.0"
  },
  "scripts": {
    "lint": "npm run lint -r",
    "test": "npm run test -r",
    "build": "npm run build -r",
    "clean": "npm run clean -r"
  }
}
```

### 2. **Lerna Configuration**

```json
{
  "name": "monorepo-with-lerna",
  "version": "1.0.0",
  "private": true,
  "packages": [
    "packages/*",
    "apps/*"
  ],
  "command": {
    "bootstrap": {
      "hoist": true,
      "ignore": "@myorg/infra"
    },
    "publish": {
      "conventionalCommits": true,
      "createRelease": "github",
      "message": "chore(release): publish"
    }
  }
}
```

### 3. **Turborepo Configuration**

```json
{
  "turbo": {
    "globalDependencies": ["tsconfig.json"],
    "pipeline": {
      "build": {
        "dependsOn": ["^build"],
        "outputs": ["dist/**", ".next/**"],
        "cache": true
      },
      "test": {
        "dependsOn": ["^build"],
        "cache": true,
        "outputs": ["coverage/**"]
      },
      "lint": {
        "outputs": []
      },
      "dev": {
        "cache": false,
        "persistent": true
      }
    }
  }
}
```

### 4. **Nx Workspace Configuration**

```json
{
  "version": 2,
  "projectNameAndRootFormat": "as-provided",
  "plugins": [
    "@nx/next/plugin",
    "@nx/react/plugin",
    "@nx/node/plugin"
  ],
  "targetDefaults": {
    "build": {
      "cache": true,
      "inputs": [
        "production",
        "^production"
      ]
    },
    "test": {
      "cache": true,
      "inputs": [
        "default",
        "^production"
      ]
    }
  }
}
```

### 5. **Monorepo Directory Structure**

```bash
monorepo/
├── packages/
│   ├── core/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   ├── utils/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── shared/
│       ├── src/
│       ├── package.json
│       └── tsconfig.json
├── apps/
│   ├── web/
│   │   ├── pages/
│   │   ├── package.json
│   │   └── next.config.js
│   ├── api/
│   │   ├── src/
│   │   ├── package.json
│   │   └── tsconfig.json
│   └── mobile/
│       ├── src/
│       ├── package.json
│       └── app.json
├── tools/
│   ├── scripts/
│   └── generators/
├── lerna.json
├── turbo.json
├── nx.json
├── package.json
├── tsconfig.json
└── .github/workflows/
```

### 6. **Workspace Dependencies**

```json
{
  "name": "@myorg/web-app",
  "version": "1.0.0",
  "dependencies": {
    "@myorg/core": "workspace:*",
    "@myorg/shared-ui": "workspace:^",
    "@myorg/utils": "workspace:~"
  },
  "devDependencies": {
    "@myorg/test-utils": "workspace:*"
  }
}
```

### 7. **Lerna Commands**

```bash
# Bootstrap packages and install dependencies
lerna bootstrap

# Install dependencies and hoist common ones
lerna bootstrap --hoist

# Create a new version
lerna version --conventional-commits

# Publish all changed packages
lerna publish from-git

# Run command across all packages
lerna exec -- npm run build

# Run command in parallel
lerna exec --parallel -- npm run test

# List all packages
lerna list

# Show graph of dependencies
lerna graph

# Run script across specific packages
lerna run build --scope="@myorg/core" --include-dependents
```

### 8. **Turborepo Commands**

```bash
# Build all packages with dependency order
turbo run build

# Build with specific filters
turbo run build --filter=web --filter=api

# Build excluding certain packages
turbo run build --filter='!./apps/mobile'

# Run tests with caching
turbo run test --cache-dir=.turbo

# Run in development mode (no cache)
turbo run dev --parallel

# Show execution graph
turbo run build --graph

# Profile build times
turbo run build --profile=profile.json
```

### 9. **CI/CD for Monorepo**

```yaml
# .github/workflows/monorepo-ci.yml
name: Monorepo CI

on: [push, pull_request]

jobs:
  affected:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0

      - uses: actions/setup-node@v3
        with:
          node-version: '18'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Get changed packages
        id: changed
        run: |
          npx lerna changed --json > changed.json
          echo "packages=$(cat changed.json | jq -r '.[].name')" >> $GITHUB_OUTPUT

      - name: Build changed
        run: npx turbo run build --filter='${{ steps.changed.outputs.packages }}'

      - name: Test changed
        run: npx turbo run test --filter='${{ steps.changed.outputs.packages }}'

      - name: Lint changed
        run: npx turbo run lint --filter='${{ steps.changed.outputs.packages }}'
```

### 10. **Version Management Across Packages**

```bash
#!/bin/bash
# sync-versions.sh

# Use lerna to keep versions in sync
lerna version --exact --force-publish

# Or manually sync package.json versions
MONOREPO_VERSION=$(jq -r '.version' package.json)

for package in packages/*/package.json; do
    jq --arg version "$MONOREPO_VERSION" '.version = $version' "$package" > "$package.tmp"
    mv "$package.tmp" "$package"
done

echo "✅ All packages synced to version $MONOREPO_VERSION"
```

## Best Practices

### ✅ DO
- Use workspace protocols for dependencies
- Implement shared tsconfig for consistency
- Cache build outputs in CI/CD
- Filter packages in CI to avoid unnecessary builds
- Hoist common dependencies
- Document workspace structure
- Use consistent versioning strategy
- Implement pre-commit hooks across workspace
- Test cross-package dependencies
- Version packages independently when appropriate

### ❌ DON'T
- Create circular dependencies
- Use hardcoded versions for workspace packages
- Build all packages when only one changed
- Forget to update lock files
- Ignore workspace boundaries
- Create tightly coupled packages
- Skip dependency management
- Use different tooling per package

## Workspace Dependency Resolution

```bash
# workspace:* - Use exact version in workspace
"@myorg/core": "workspace:*"

# workspace:^ - Use compatible version
"@myorg/shared": "workspace:^"

# workspace:~ - Use patch-compatible version
"@myorg/utils": "workspace:~"
```

## Resources

- [Lerna Documentation](https://lerna.js.org/)
- [Turborepo Documentation](https://turbo.build/repo/docs)
- [Nx Documentation](https://nx.dev/)
- [npm Workspaces](https://docs.npmjs.com/cli/v7/using-npm/workspaces)

Overview

This skill helps teams design, configure, and operate monorepo architectures using Lerna, Turborepo, and Nx. It focuses on workspace configuration, dependency versioning, cross-package testing, and CI/CD optimization to keep builds fast and reproducible. The goal is scalable workflows for multi-package projects and multi-app platforms.

How this skill works

The skill inspects workspace manifests, tooling configs (lerna.json, turbo.json, nx.json, package.json), and directory layout to recommend structure and commands. It produces configuration snippets for npm workspaces, Lerna bootstrapping, Turborepo pipelines, and Nx target defaults. It also suggests CI steps to compute affected packages, cache outputs, and run filtered builds and tests.

When to use it

  • When a repository contains multiple packages, apps, or shared libraries
  • If teams need coordinated versioning and cross-package testing
  • For microservices or plugin-based systems sharing code
  • When CI times grow and you need to build only affected packages
  • To adopt workspace protocols and hoist common dependencies

Best practices

  • Use workspace protocols (workspace:*, workspace:^, workspace:~) for local deps
  • Share tsconfig and lint rules to ensure consistency across packages
  • Cache build outputs in CI and filter builds to affected packages
  • Hoist common dependencies to reduce install time and dedupe versions
  • Avoid circular dependencies and document workspace boundaries

Example use cases

  • Set up npm workspaces with packages/* and apps/* and central scripts for lint/test/build
  • Configure Turborepo pipeline to cache build and test outputs and run dev without cache
  • Use Lerna to bootstrap, hoist dependencies, and publish changed packages with conventional commits
  • Create a CI job that uses Lerna to list changed packages and Turbo to build/test only those
  • Sync package versions across packages via a small script or lerna version for coordinated releases

FAQ

How do I avoid building everything on every change?

Use tooling that supports affected/filtered runs (turbo run --filter, lerna changed or affected), cache outputs in CI, and configure pipelines to depend on upstream targets so only impacted packages run.

When should I hoist dependencies?

Hoist when many packages share the same dependency and you want faster installs and smaller lockfiles; avoid hoisting packages that need different versions or platform-specific builds.