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
| Benefit | Challenge |
|---|---|
| Code sharing | Build complexity |
| Atomic changes | CI time |
| Consistency | Permission management |
| Visibility | Tooling 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
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