Monorepo vs Polyrepo: Choosing the Right Repository Strategy in 2026
Author
ZTABS Team
Date Published
At some point, every growing engineering team faces the same question: should all our code live in one repository, or should each project get its own? The answer depends on your team size, deployment model, and how tightly coupled your packages are.
This guide cuts through the hype around monorepos and gives you a practical framework for choosing — and implementing — the right strategy.
What Is a Monorepo?
A monorepo is a single repository that contains multiple projects, packages, or services. It does not mean a monolith — the code inside is still modular. The key difference is that all modules share one version history, one CI pipeline configuration, and one dependency tree.
my-monorepo/
├── apps/
│ ├── web/ # Next.js frontend
│ ├── api/ # Express backend
│ └── mobile/ # React Native app
├── packages/
│ ├── ui/ # Shared component library
│ ├── config/ # Shared ESLint, TypeScript configs
│ ├── utils/ # Shared utility functions
│ └── database/ # Prisma schema and client
├── turbo.json
├── pnpm-workspace.yaml
└── package.json
Google, Meta, Microsoft, and Uber all use monorepos at massive scale. But their tooling is custom-built. For the rest of us, the open-source ecosystem has caught up with tools like Turborepo, Nx, and pnpm workspaces.
What Is a Polyrepo?
A polyrepo strategy gives each project its own repository. Teams own their repos, control their release cadence, and choose their own tooling.
github.com/company/web-app # Next.js frontend
github.com/company/api-service # Express backend
github.com/company/mobile-app # React Native app
github.com/company/ui-library # Published to npm
github.com/company/shared-utils # Published to npm
Shared code is distributed through a package registry (npm, GitHub Packages) rather than through direct imports.
Side-by-Side Comparison
| Factor | Monorepo | Polyrepo | |--------|----------|----------| | Code sharing | Direct imports, instant | Via package registry, versioned | | Dependency management | Single lockfile, unified versions | Independent per repo | | Atomic changes | Cross-project changes in one PR | Coordinated PRs across repos | | CI/CD | Needs smart task orchestration | Standard per-repo pipelines | | Team autonomy | Shared conventions required | Full independence | | Onboarding | One clone, everything available | Clone only what you need | | Git performance | Can degrade at scale | Always fast | | Access control | Harder to restrict | Native per-repo permissions | | Release coordination | Easier (everything in sync) | Harder (version compatibility) |
Monorepo Tooling: The Big Three
Turborepo
Turborepo is the simplest path to a fast monorepo. Built by Vercel, it focuses on one thing: running tasks (build, test, lint) across packages in the right order, as fast as possible.
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"test": {
"dependsOn": ["build"]
},
"lint": {},
"dev": {
"cache": false,
"persistent": true
}
}
}
Key features:
- Incremental builds — only rebuilds what changed
- Remote caching — share build artifacts across CI and developers
- Task pipeline — declare dependencies between tasks, Turborepo parallelizes the rest
- Zero config — works with any package manager
# Run builds for all packages, respecting dependency order
turbo build
# Run only affected packages (based on git diff)
turbo build --filter=...[HEAD^1]
# Run dev servers for the web app and its dependencies
turbo dev --filter=web...
Nx
Nx is the most feature-rich monorepo tool. It provides everything Turborepo does, plus code generation, dependency graph visualization, and deep framework integrations.
// nx.json
{
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"cache": true
},
"test": {
"cache": true
},
"lint": {
"cache": true
}
},
"defaultBase": "main"
}
# Build only affected projects
nx affected --target=build
# Visualize the dependency graph
nx graph
# Generate a new library
nx generate @nx/react:library shared-ui
Best for: large teams that want opinionated structure, code generation, and deep IDE integration.
pnpm Workspaces
pnpm workspaces provide the foundation layer — package linking and dependency hoisting — without task orchestration. Many teams use pnpm workspaces with Turborepo or Nx on top.
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
// packages/ui/package.json
{
"name": "@company/ui",
"version": "1.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --dts --watch"
}
}
// apps/web/package.json
{
"name": "web",
"dependencies": {
"@company/ui": "workspace:*",
"@company/utils": "workspace:*"
}
}
The workspace:* protocol tells pnpm to link directly to the local package instead of downloading from a registry.
Tool Comparison
| Feature | Turborepo | Nx | pnpm Workspaces | |---------|-----------|-----|-----------------| | Task orchestration | Yes | Yes | No (needs scripts) | | Remote caching | Yes (Vercel) | Yes (Nx Cloud) | No | | Code generation | No | Yes (extensive) | No | | Dependency graph | Basic | Advanced + visual | No | | Framework plugins | None needed | React, Angular, Node | None | | Learning curve | Low | Medium-High | Low | | Config overhead | Minimal | Moderate | Minimal |
Build Caching: The Monorepo Superpower
The biggest performance advantage of monorepos is build caching. If a package has not changed since the last build, skip it entirely and use the cached output.
Local Caching
Turborepo caches task outputs in .turbo/cache by default. If you run turbo build twice without changing anything, the second run completes in milliseconds.
Remote Caching
Remote caching shares build artifacts across your entire team and CI. When a developer builds a package locally, the output is uploaded to the cache. When CI runs the same build, it downloads the cached output instead of rebuilding.
# Enable remote caching with Vercel
npx turbo login
npx turbo link
In CI, set the TURBO_TOKEN and TURBO_TEAM environment variables and remote caching works automatically.
The impact is dramatic. A full rebuild that takes 8 minutes might complete in 30 seconds when most packages are cached.
Dependency Management
Monorepo: Unified Dependencies
In a monorepo, all packages share a single lockfile. This means every package uses the same version of React, TypeScript, or any other dependency.
// Root package.json
{
"devDependencies": {
"typescript": "^5.5.0",
"eslint": "^9.0.0",
"prettier": "^3.3.0"
}
}
Shared configurations live in a dedicated package:
// packages/config/tsconfig/base.json
{
"compilerOptions": {
"strict": true,
"target": "ES2022",
"module": "ESNext",
"moduleResolution": "bundler",
"jsx": "react-jsx",
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}
Each app extends the shared config:
// apps/web/tsconfig.json
{
"extends": "@company/config/tsconfig/nextjs.json",
"compilerOptions": {
"paths": {
"@/*": ["./src/*"]
}
},
"include": ["src", "next-env.d.ts"],
"exclude": ["node_modules"]
}
Polyrepo: Versioned Dependencies
In a polyrepo, shared code is published to a package registry. Version management becomes the critical concern.
// In your web app repo
{
"dependencies": {
"@company/ui": "^2.3.0",
"@company/utils": "^1.7.0"
}
}
This means you need a publishing workflow, semantic versioning discipline, and a strategy for breaking changes. Tools like Changesets help automate this.
When to Choose a Monorepo
Choose a monorepo when:
- Packages are tightly coupled — your frontend and backend share types, your component library is consumed by multiple apps, and changes often span packages
- You want atomic changes — a single PR can update the API, the types, and the frontend that consumes them
- Team size is moderate (5–50 engineers) — large enough to benefit from code sharing, small enough that everyone can work in one repo
- You release together — your apps deploy in coordination and need compatible versions
When to Choose a Polyrepo
Choose a polyrepo when:
- Teams are autonomous — each team owns their service, their release cadence, and their tech decisions
- Services are loosely coupled — they communicate via well-defined APIs and rarely need synchronized changes
- You have strict access control needs — different teams, contractors, or partners need different repository permissions
- Scale demands it — hundreds of developers working on truly independent services
The Hybrid Approach
Many organizations use a hybrid: a monorepo for tightly coupled packages (the frontend apps and shared libraries) and separate repos for independent services (infrastructure, data pipelines, mobile apps with different build toolchains).
github.com/company/platform # Monorepo: web, api, shared packages
github.com/company/infrastructure # Polyrepo: Terraform, Pulumi
github.com/company/data-pipeline # Polyrepo: Python/Spark
github.com/company/ios-app # Polyrepo: Swift/Xcode
This gives you atomic cross-cutting changes where they matter most, without forcing unrelated projects into one repository.
Migrating to a Monorepo
If you are moving from polyrepo to monorepo, do it incrementally.
- Start with the build system — set up Turborepo + pnpm workspaces with your most active app
- Move shared packages first — extract common utilities, configs, and types into
packages/ - Move apps one at a time — bring each app into the monorepo as a separate PR
- Preserve git history — use
git subtreeto merge repos while keeping commit history - Update CI/CD — configure affected-only builds so CI does not rebuild everything on every commit
# Merge a repo into the monorepo preserving history
git subtree add --prefix=apps/web \
git@github.com:company/web-app.git main
Getting Started
Repository strategy is a foundational web development decision that affects developer experience, CI performance, and team collaboration for years. Getting it right early helps control web app development costs and avoid painful migrations later.
If you are starting a new project or considering a migration, talk to our team. We help companies design and implement monorepo architectures using Turborepo, Nx, and pnpm — with CI/CD pipelines that stay fast as the codebase grows.
Choose the right structure for your team. Build the tooling to support it. Ship faster.
Explore Related Solutions
Need Help Building Your Project?
From web apps and mobile apps to AI solutions and SaaS platforms — we ship production software for 300+ clients.
Related Articles
API Security Best Practices: A Developer Guide for 2026
A practical guide to securing APIs in production. Covers OAuth 2.0, JWT handling, rate limiting, input validation, CORS configuration, API key management, and security headers with real code examples.
12 min readDatabase Scaling Strategies: From Single Server to Global Scale
A practical guide to database scaling strategies for growing applications. Covers vertical and horizontal scaling, read replicas, sharding, connection pooling, caching layers, and partition strategies with real SQL examples.
8 min readGraphQL vs REST API: When to Use Each in 2026
A practical comparison of GraphQL and REST for modern applications. Covers over-fetching, the N+1 problem, schema stitching, performance tradeoffs, and clear guidance on when each approach wins.