Monorepo to Polyrepo:
When and How to Split (2026)

Most content assumes consolidation is the direction. But real teams split monorepos too: acquisitions, regulatory boundaries, scale failures, org changes. Here is when splitting is correct and how to do it.

When to Split: Legitimate Triggers

Acquisition or spinout

A business unit is sold or spun out. Repo isolation is the right call regardless of engineering preference. Shared code becomes a shared library published to a private registry.

Regulatory boundaries

FedRAMP, FINRA, SOC 2 Type II, HIPAA, or GDPR requirements may mandate repository isolation between systems with different compliance scopes. Auditors expect clean boundaries.

Sustained CI scale failure

Your monorepo build has grown beyond what affected + caching can handle. Even with distributed builds, CI time is measured in hours per push. This is rare but real at 500+ engineers.

Org restructuring across domains

When two product domains that shared a monorepo become separate P&L units or separate teams with no coordination need, splitting removes the organisational overhead of shared-repo governance.

Third-party code isolation

Vendor code, open-source forks, or acquired codebases with different licensing requirements are cleanest in isolated repos.

The Split Playbook

01

Identify clean module boundaries

Run nx graph or your tool's dep graph to visualise cross-package dependencies. Look for packages with no inbound dependencies from the packages you want to split out. Tight coupling (circular deps, frequent cross-imports) makes splitting expensive.

02

Extract with git filter-repo or git subtree split

git filter-repo --path packages/my-service --path packages/shared-lib preserves only the commits that touched those paths. The result is a new repo with full history for only those paths.

# Extract with git filter-repo (recommended over git filter-branch)
git clone --bare git@github.com:org/monorepo.git monorepo-extract
cd monorepo-extract
git filter-repo --path packages/my-service/ --path-rename packages/my-service/:src/
# Push to new repo
git remote add origin git@github.com:org/my-service.git
git push -u origin --all
03

Set up shared library publishing

Shared code that stays in the monorepo must now be consumed via a published package. Set up a private npm registry (GitHub Packages, Verdaccio, Nexus, npm org private) and publish the shared packages. Bump versions before the cutover.

04

Set up a dependency dashboard

Polyrepo dependency drift is real. Set up Renovate or Dependabot on the split repos to keep shared-lib versions aligned. Without this, repos will silently drift onto incompatible versions.

05

Migrate CI per extracted repo

Each split repo needs its own CI pipeline. This is the most time-consuming step for large splits. Budget 1-2 days per repo to port the relevant CI config. Most teams underestimate this.

Common Failure Modes When Splitting

Over-coupling preventing a clean split

If packages/service-a imports from packages/service-b which imports from service-a, there is no clean extraction point. You must first decouple, then split. Plan 2-4 weeks for decoupling before the split.

Lost atomicity after split

The monorepo's atomic commit across services no longer exists after splitting. You must replace it with: versioned APIs, contract tests (Pact, OpenAPI), and staged rollout procedures.

Sync drift on shared types

Shared TypeScript types or protobuf schemas published as packages can drift. Enforce version pinning via Renovate lockfile maintenance and pre-merge compatibility checks.

Going the other direction? →Migration cost data →