Monorepo vs Polyrepo
Also Known As
TL;DR
Explanation
A monorepo hosts multiple PHP packages, microservices, or applications in a single git repository. Benefits: atomic cross-service commits (change an API and its consumers in one PR), shared tooling and CI configuration, easier code sharing and refactoring across packages, unified dependency management. Challenges: repo size grows large, CI must run only affected tests (tools like Nx, Turborepo, or GitHub Actions path filters), and access control is coarser-grained. Polyrepos give each service independent versioning, deployment, and access control — better for teams that need autonomy, or when services have genuinely separate lifecycles. PHP monorepo tooling: symplify/monorepo-builder for synchronising composer.json files across packages; Composer path repositories for local package linking.
Common Misconception
Why It Matters
Common Mistakes
- No build caching — CI rebuilds every package on every commit regardless of what changed.
- Treating a monorepo as a monolith — packages should still have clear boundaries and independent versioning.
- Not using workspace tools (Turborepo, Nx, Composer workspaces) — manual management is error-prone.
- Shared dependencies that force all packages to upgrade together — defeats package independence.
Code Examples
# Monorepo without caching — rebuilds everything on every commit:
# packages/api changed
# CI runs: build:api build:web build:mobile build:docs
# Only api needed rebuilding — wasted 10 minutes
# With Turborepo cache:
# build:api — cache miss, runs (1 min)
# build:web — cache hit, skipped
# build:mobile — cache hit, skipped
// PHP monorepo with multiple packages managed by Composer
// Structure:
// packages/
// core/ composer.json, src/, tests/
// payments/ composer.json, src/, tests/
// notifications/composer.json, src/, tests/
// composer.json (root — manages all packages)
// root composer.json:
{
"repositories": [
{"type": "path", "url": "packages/*"}
],
"require": {
"myapp/core": "@dev",
"myapp/payments": "@dev",
"myapp/notifications": "@dev"
}
}
// Run tests across all packages:
$ find packages -name phpunit.xml | xargs -I{} dirname {} | xargs -I{} bash -c 'cd {} && vendor/bin/phpunit'
// Tool: https://github.com/symplify/monorepo-builder
$ vendor/bin/monorepo-builder release 2.5.0 // bumps all package versions