ADR 003: Hybrid Monorepo + Polyrepo Strategy
Status: Accepted Date: 2025-03-15 Last Updated: 2026-02-26
Context
We have shared libraries (design system, types, configs) and 5-10 independently deployable micro frontends maintained by 3-5 teams. We need a repository strategy that balances code sharing with team autonomy.
Decision
Hybrid approach: a monorepo (platform-core) for shared packages (design system, types, utils, configs) using pnpm 10.30.3 workspaces + Turborepo, and separate polyrepos for each micro frontend. Shared packages target React ^19.2.4.
Consequences
Positive
- Shared packages benefit from atomic changes (update design system + types in one PR)
- MFE teams have full autonomy: own CI/CD, own branch strategy, own release cadence
- Separate access control per MFE repo
- Monorepo changes propagated via Changesets → npm publish → Renovate
- No need to rebuild all MFEs when shared lib changes (only affected ones via Renovate PRs)
- Simpler CI for each MFE (only builds one MFE, not the whole platform)
Negative
- Cross-repo dependency updates have latency (publish → Renovate → merge)
- Testing integration across repos requires Verdaccio or yalc
- Developers working on both shared lib and MFE need two repos open
- Renovate/Dependabot management across multiple repos
- Shared package versioning requires discipline (Changesets helps)
Shared Package Deprecation Guidance
When deprecating a shared package from the platform-core monorepo, follow this process:
- Deprecation Notice: Add a
## Deprecatedentry at the top of the package's CHANGELOG with the deprecation date, reason, and recommended replacement (if any). - Migration Guide: Publish a migration guide in the package's README or a dedicated
MIGRATION.mdfile that explains step-by-step how consuming MFEs should migrate away from the deprecated package. - Minimum Support Window: Maintain the deprecated package for a minimum of 90 days (3 release cycles) after the deprecation notice. During this window, critical security patches must still be applied.
- Renovate Notification: Configure Renovate to add a deprecation warning label to PRs that still depend on the deprecated package.
- Removal Procedure: After the support window expires and all consuming MFEs have migrated (verified via npm download stats and Renovate dashboards), remove the package from the monorepo workspace and publish a final version with a
postinstallscript that prints a deprecation warning.
Alternatives Considered
- Full monorepo (all MFEs + shared libs): Simpler dependency management, atomic cross-cutting changes. But: huge CI times, all teams in one repo creates merge conflicts, access control is coarse-grained, can't have independent deploy pipelines easily. Doesn't scale well past 3 teams.
- Full polyrepo (everything separate): Maximum team autonomy. But: shared package versioning nightmare, no atomic changes across shared libs, config drift across repos, duplicate tooling setup. Cross-cutting refactors require coordinated PRs across 10+ repos.
- Git submodules: Technical solution for sharing code across repos. But: complex workflow, merge conflicts in submodule references, poor developer experience, most teams dislike working with submodules.