Monorepos
Code organization strategy where multiple projects coexist in a single repository, sharing dependencies, configuration, and build tooling.
A monorepo is a single repository containing multiple distinct projects with well-defined relationships between them. It's not just "all code in one folder" — it's an architectural strategy backed by specialized tooling.
What problem it solves
In a polyrepo model (one repository per project), teams face:
- Dependency hell — syncing versions across repos is manual and error-prone
- Impossible atomic changes — a refactor touching 3 repos requires 3 coordinated PRs
- Configuration duplication — ESLint, TypeScript, CI/CD copied into every repo
- Difficult discovery — where is the code I need? What version does the other team use?
The monorepo centralizes everything in one place with tools that manage the complexity.
When to use it
Good fit when:
- Multiple packages share common code (types, utilities, components)
- The team needs atomic changes that cross boundaries
- You want a single source of truth for configuration (linting, testing, CI)
- Projects have coordinated release cycles
Avoid when:
- Projects are completely independent with no shared code
- Teams have very different release cycles
- Strict access restrictions are required (monorepos imply shared visibility)
- The repo would grow to sizes Git can't handle well (>10GB, millions of files)
Main tools
| Tool | Focus | Language | Key features |
|---|---|---|---|
| Turborepo | Build caching | JS/TS | Remote cache, declarative pipelines, zero-config |
| Nx | Full-featured | JS/TS | Generators, affected commands, graph visualization |
| pnpm workspaces | Package manager | JS/TS | Efficient symlinks, strict dependencies |
| Lerna | Publishing | JS/TS | Coordinated versioning, changelogs (now part of Nx) |
| Bazel | Hermetic builds | Polyglot | Reproducibility, extreme scalability (Google-scale) |
| Pants | Hermetic builds | Python/Go/Java | Similar to Bazel, better DX |
| Rush | Enterprise | JS/TS | Strict policies, phantom dependencies detection |
Turborepo vs Nx
The most common comparison in the JavaScript ecosystem:
Turborepo — minimalist, integrates with your existing setup, excellent remote cache with Vercel. Ideal if you already have a monorepo and want to speed up builds without changing much.
Nx — more opinionated, includes generators for scaffolding, framework-specific plugins, dependency visualization. Better if starting from scratch or wanting guided structure.
Typical structure
monorepo/
├── apps/
│ ├── web/ # Next.js app
│ ├── mobile/ # React Native app
│ └── api/ # Backend service
├── packages/
│ ├── ui/ # Shared components
│ ├── utils/ # Shared utilities
│ └── config/ # Shared ESLint, TS configs
├── turbo.json # Pipeline configuration
├── pnpm-workspace.yaml
└── package.json
Key patterns
1. Internal packages
Packages that are never published to npm — only consumed within the monorepo:
{
"name": "@repo/ui",
"private": true,
"exports": {
".": "./src/index.ts"
}
}2. Task pipelines
Define dependencies between tasks for correct parallelization:
{
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"]
}
}
}3. Remote caching
A package build that hasn't changed is retrieved from cache instead of re-executing:
# First time: runs build
turbo build # 45s
# Second time (no changes): retrieved from cache
turbo build # 0.3sAnti-patterns
- Monolith in disguise — everything in one repo but no clear boundaries between packages
- Cache without proper invalidation — builds that don't detect changes in dependencies
- Circular dependencies — package A imports B which imports A
- God package — a
@repo/utilsthat grows unchecked and everything depends on
This site is a monorepo
jonmatum.com uses Turborepo + pnpm workspaces with apps/web (Next.js) and packages/knowledge (content pipeline). Turborepo's cache reduces the build from ~45s to under 1s when only MDX content changes.
Why it matters
The decision between monorepo and polyrepo affects development velocity, CI/CD complexity, and the ability to share code across teams. There is no universal answer — but understanding the trade-offs prevents months of painful migration when the initial choice doesn't scale.
References
- Monorepo Explained — Nrwl, 2023. Exhaustive comparison of tools and patterns.
- Turborepo Handbook — Vercel, 2024. Official guide with best practices.
- Why Google Stores Billions of Lines of Code in a Single Repository — Google Research, 2016. The seminal paper on monorepos at scale.
- Monorepos: Please don't! — Matt Klein, 2019. Critical perspective on when to avoid them.