GitScrum / Docs
All Best Practices

Monorepo Management | Structure, Builds & CI/CD

Manage monorepos with incremental builds, remote caching, and affected detection. GitScrum tracks cross-package work with ownership and dependencies.

6 min read

Monorepos house multiple projects in a single repository. Done well, they simplify sharing and consistency. Done poorly, they become slow, confusing, and hard to maintain. This guide covers practical approaches to monorepo management.

Monorepo Trade-offs

BenefitChallenge
Code sharingBuild complexity
Atomic changesCI time
ConsistencyPermission management
VisibilityTooling required

Repository Structure

Organizing the Monorepo

MONOREPO STRUCTURE
══════════════════

TYPICAL STRUCTURE:
─────────────────────────────────────
monorepo/
β”œβ”€β”€ apps/                    # Applications
β”‚   β”œβ”€β”€ web/                # Web frontend
β”‚   β”œβ”€β”€ api/                # Backend API
β”‚   β”œβ”€β”€ mobile/             # Mobile app
β”‚   └── admin/              # Admin dashboard
β”œβ”€β”€ packages/               # Shared libraries
β”‚   β”œβ”€β”€ ui/                # UI components
β”‚   β”œβ”€β”€ utils/             # Utilities
β”‚   β”œβ”€β”€ config/            # Shared config
β”‚   └── types/             # Type definitions
β”œβ”€β”€ tools/                  # Build tools
β”‚   └── scripts/
β”œβ”€β”€ package.json           # Root package
β”œβ”€β”€ nx.json / turbo.json   # Monorepo tool config
└── README.md

NAMING CONVENTIONS:
─────────────────────────────────────
Packages:
β”œβ”€β”€ @org/web (apps)
β”œβ”€β”€ @org/api (apps)
β”œβ”€β”€ @org/ui (packages)
β”œβ”€β”€ @org/utils (packages)
β”œβ”€β”€ Scoped naming
└── Clear ownership

OWNERSHIP:
─────────────────────────────────────
Define owners:
β”œβ”€β”€ apps/web β†’ Web Team
β”œβ”€β”€ apps/api β†’ Backend Team
β”œβ”€β”€ packages/ui β†’ Design Systems Team
β”œβ”€β”€ packages/utils β†’ Platform Team
β”œβ”€β”€ CODEOWNERS file
└── Clear responsibility

Dependency Management

Internal Dependencies

DEPENDENCY MANAGEMENT
═════════════════════

INTERNAL DEPENDENCIES:
─────────────────────────────────────
apps/web/package.json:
{
  "dependencies": {
    "@org/ui": "workspace:*",
    "@org/utils": "workspace:*"
  }
}

Using workspace protocol:
β”œβ”€β”€ Links to local package
β”œβ”€β”€ No version management
β”œβ”€β”€ Always uses current
β”œβ”€β”€ Atomic updates
└── Simple internal deps

DEPENDENCY GRAPH:
─────────────────────────────────────
           β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
           β”‚  apps   β”‚
           β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                β”‚ depends on
           β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
           β”‚packages β”‚
           β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”˜
                β”‚ may depend on
           β”Œβ”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”
           β”‚packages β”‚
           β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Rules:
β”œβ”€β”€ Apps depend on packages
β”œβ”€β”€ Packages can depend on packages
β”œβ”€β”€ No circular dependencies
β”œβ”€β”€ Packages don't depend on apps
└── Clear hierarchy

EXTERNAL DEPENDENCIES:
─────────────────────────────────────
Strategies:
β”œβ”€β”€ Hoist to root (same version)
β”œβ”€β”€ Or allow per-package versions
β”œβ”€β”€ Consistency preferred
β”œβ”€β”€ Regular update cadence
└── Dependency health

HOISTING EXAMPLE:
─────────────────────────────────────
Root package.json:
{
  "devDependencies": {
    "typescript": "5.0.0",
    "jest": "29.0.0",
    "eslint": "8.0.0"
  }
}

β”œβ”€β”€ All packages use same version
β”œβ”€β”€ Single lock file
β”œβ”€β”€ Consistent tooling
└── Simpler updates

Build System

Efficient Builds

BUILD SYSTEM
════════════

INCREMENTAL BUILDS:
─────────────────────────────────────
Only build what changed:
β”œβ”€β”€ Detect affected packages
β”œβ”€β”€ Build only those + dependents
β”œβ”€β”€ Cache results
β”œβ”€β”€ Reuse unchanged
└── Fast feedback

EXAMPLE (Nx):
─────────────────────────────────────
# Build only affected
nx affected:build

# Test only affected
nx affected:test

# Lint only affected
nx affected:lint

REMOTE CACHING:
─────────────────────────────────────
β”œβ”€β”€ Cache build artifacts
β”œβ”€β”€ Share across team
β”œβ”€β”€ CI cache hit
β”œβ”€β”€ Massive time savings
β”œβ”€β”€ Nx Cloud, Turborepo Remote Cache
└── Essential for scale

BUILD GRAPH:
─────────────────────────────────────
nx graph

Shows:
β”œβ”€β”€ Package dependencies
β”œβ”€β”€ Build order
β”œβ”€β”€ Affected by change
β”œβ”€β”€ Visual understanding
└── Dependency clarity

PARALLEL EXECUTION:
─────────────────────────────────────
β”œβ”€β”€ Build independent packages in parallel
β”œβ”€β”€ Respect dependency order
β”œβ”€β”€ Utilize all cores
β”œβ”€β”€ Faster CI
└── Concurrent where possible

CI/CD

Pipeline Configuration

CI/CD FOR MONOREPOS
═══════════════════

AFFECTED DETECTION:
─────────────────────────────────────
# Only run for affected
- name: Build affected
  run: npx nx affected:build --base=main

- name: Test affected
  run: npx nx affected:test --base=main

Benefits:
β”œβ”€β”€ PR only builds changed code
β”œβ”€β”€ Fast feedback
β”œβ”€β”€ Less CI time
└── Efficient resources

CACHING:
─────────────────────────────────────
# Cache node_modules
- uses: actions/cache@v3
  with:
    path: node_modules
    key: deps-${{ hashFiles('pnpm-lock.yaml') }}

# Cache build outputs
- uses: actions/cache@v3
  with:
    path: dist
    key: build-${{ github.sha }}

PARALLEL JOBS:
─────────────────────────────────────
jobs:
  build-web:
    if: needs.changes.outputs.web == 'true'
  build-api:
    if: needs.changes.outputs.api == 'true'
  build-ui:
    if: needs.changes.outputs.ui == 'true'

β”œβ”€β”€ Parallel per-package
β”œβ”€β”€ Only if affected
β”œβ”€β”€ Fast CI
└── Efficient

DEPLOY STRATEGY:
─────────────────────────────────────
β”œβ”€β”€ Independent app deploys
β”œβ”€β”€ Only deploy changed apps
β”œβ”€β”€ Packages don't deploy (published)
β”œβ”€β”€ Clear deploy triggers
└── Targeted deployments

Team Practices

Working Together

TEAM PRACTICES
══════════════

CODE OWNERSHIP:
─────────────────────────────────────
CODEOWNERS file:
/apps/web/        @web-team
/apps/api/        @backend-team
/packages/ui/     @design-systems
/packages/utils/  @platform-team

β”œβ”€β”€ Required reviews
β”œβ”€β”€ Clear ownership
β”œβ”€β”€ Right reviewers
└── Accountability

BRANCH STRATEGY:
─────────────────────────────────────
β”œβ”€β”€ Feature branches from main
β”œβ”€β”€ PRs reviewed by owners
β”œβ”€β”€ Main always deployable
β”œβ”€β”€ No long-lived branches
└── Trunk-based development

CHANGE COORDINATION:
─────────────────────────────────────
For cross-package changes:
β”œβ”€β”€ Single PR (atomic)
β”œβ”€β”€ Multiple owners review
β”œβ”€β”€ Test all affected
β”œβ”€β”€ Deploy together
└── Coordinated change

DOCUMENTATION:
─────────────────────────────────────
β”œβ”€β”€ Root README: Overview
β”œβ”€β”€ Each package: Own README
β”œβ”€β”€ Architecture docs
β”œβ”€β”€ Contribution guide
└── Findable documentation

GitScrum Integration

Tracking Work

GITSCRUM FOR MONOREPOS
══════════════════════

PROJECT ORGANIZATION:
─────────────────────────────────────
Options:
β”œβ”€β”€ Single project (whole monorepo)
β”œβ”€β”€ Project per app
β”œβ”€β”€ Team-based projects
β”œβ”€β”€ Choose based on org structure
└── What makes sense for you

LABELS:
─────────────────────────────────────
β”œβ”€β”€ app:web
β”œβ”€β”€ app:api
β”œβ”€β”€ package:ui
β”œβ”€β”€ package:utils
β”œβ”€β”€ cross-package
└── Clear categorization

CROSS-PACKAGE TASKS:
─────────────────────────────────────
Task: "Add dark mode support"
β”œβ”€β”€ packages/ui: Dark theme
β”œβ”€β”€ apps/web: Theme switcher
β”œβ”€β”€ Linked sub-tasks
β”œβ”€β”€ Track together
└── Atomic feature

Best Practices

For Monorepos

  • Invest in tooling β€” Nx, Turborepo early
  • Clear ownership β€” CODEOWNERS enforced
  • Affected detection β€” Only build changed
  • Remote caching β€” Essential for scale
  • Consistent standards β€” Shared config
  • Anti-Patterns

    MONOREPO MISTAKES:
    βœ— No incremental builds
    βœ— No caching
    βœ— Unclear ownership
    βœ— Circular dependencies
    βœ— Everything in CI every time
    βœ— No shared tooling config
    βœ— Giant PRs across all packages
    βœ— Ignoring performance
    

    Related Solutions