"A vulnerability was found in this library; please update all systems using it"—when managing multiple systems in custom development, responding to such requests grows heavier year after year. The reason is simple: repositories are separated by system, and versions of the same library are completely inconsistent. One repository runs the latest version, another is two years behind, and yet another runs "an ancient version nobody remembers." When a vulnerability emerges, you must start by auditing "where and which versions remain," spending more time on investigation than on the update itself. As repositories multiply with each project, this "dependency drift" quietly spreads, inflating the cost of cross-cutting responses.
A notable case study tackling this problem head-on is Block 450 JVM Repositories Into Monorepo (InfoQ), reported by InfoQ in June 2026. Block consolidated 450 JVM repositories into a single monorepo to curb dependency drift. Although the scale is massive, the underlying dynamic—where distributed repositories generate dependency drift—is identical to what teams face when managing multiple systems in custom development. This article outlines how to evaluate and execute the monorepo option within the context of custom development.
Why repository sprawl causes dependency drift
Managing separate repositories per project or system makes sense initially. Each operates independently, and changes in one project do not affect another. The issue is that over time, the following challenges inevitably arise.
First, the same dependencies are declared separately in each repository. Even if Repository A and Repository B use the exact same JSON library, versions are defined independently in their respective configuration files. Updating A while forgetting B introduces drift at that exact moment. Version update decisions are left to individual repositories, falling out of sync.
Second, there is no single place to see the big picture. Knowing "which systems use this library" requires opening and checking every single repository one by one. Once repositories number in the dozens or hundreds, this audit itself becomes impractical.
Third, shared code gets duplicated. Because it is difficult to share common logic across repositories, teams often resort to copying and pasting it. Then, when a bug is found in that shared logic, you are stuck tracking down and fixing every copied instance.
Losing track of where dependencies live is directly tied to losing visibility into service connections. The approach to visualizing dependencies across an entire system was covered in our article on visualizing service dependencies; adopting a monorepo is one way to achieve that visibility by "bringing everything into a single repository."
What changes with a monorepo: maintaining a single source of truth
A monorepo is a pattern where multiple projects are managed within a single repository. Contrary to a common misconception, this does not mean "merging everything into one monolithic application." While each project remains independent, you unify only their storage location. On top of that, you enable dependency versions to be standardized in a single place.
monorepo/
├── apps/
│ ├── customer-site/ # 顧客Aのサイト(独立して動く)
│ └── admin-tool/ # 顧客Bの管理ツール(独立して動く)
├── packages/
│ └── shared-ui/ # 共通の部品(コピーせず参照する)
└── 依存バージョンの定義 # ライブラリの版を一か所で管理
With this architecture, the three issues surrounding dependencies are reversed.
| Dimension | Distributed repositories | Monorepo |
|---|---|---|
| Dependency versions | Inconsistent across repositories | Can be unified in one place |
| "Where is it used?" | Audit across all repositories | Search within a single repository |
| Shared code | Copied and duplicated | Referenced and shared once |
| Vulnerability response | Unclear where legacy versions exist | Fix once to update everywhere |
How you respond to vulnerabilities changes fundamentally. In a distributed setup, you begin by investigating "where old versions remain," but in a monorepo, you can update dependency declarations in one place and instantly search the blast radius on the spot. In custom development, you can fulfill requests to "update every system in use" without conducting an audit.
Pitfalls when adopting it in client web development
A suite of systems for a corporate group whose maintenance we took over (company name withheld) was split across more than a dozen repositories created for individual group companies, with shared authentication logic copied into each repo. When a defect was discovered in the authentication logic and patched, there was no inventory of which repositories contained duplicates of the code, ultimately taking two full days just to open and verify every repository.
We began by consolidating the "copied shared logic" into a single shared package, gradually moving each system to reference it. Instead of migrating all repositories to a monorepo at once, our policy was to transition newly built parts and sections touched during refactoring first. Dependency version definitions were also centralized starting with migrated components. As a result, the next time shared logic needed a fix, modifying a single place propagated the change to all referencing systems, completely eliminating the two-day cross-repo verification ordeal.
The most valuable lesson from this migration was not attempting monorepo consolidation "all at once". Large-scale cases like Block integrating 450 repositories look impressive, but attempting the same in custom development in one fell swoop risks halting all systems mid-migration. Starting with the consolidation of shared logic and expanding scope while verifying results is the safe approach. Documenting why a specific architecture was chosen ensures subsequent decisions remain steady. For recording architectural choices, the methods discussed in our article on ADRs (Architecture Decision Records) will prove useful.
Another pitfall is that monorepos tend to make builds and CI heavy. When everything lives in one repository, changing a single file can trigger builds and tests across the entire codebase, driving up runtimes. If you do not implement a mechanism from the start to "build and test only modified sections," development velocity drops as the price of integration. Just like repository structure, standardizing CI and infrastructure configurations in one place is effective when combined with the approach covered in our article on standardizing IaC with CDK and Terraform.
Where to begin
If repositories are multiplying with every project, library versions are inconsistent, and every vulnerability response begins with an audit, consolidating dependencies into one place is well worth considering. However, there is no need to aim for a full repository consolidation right out of the gate.
As a first step, select one piece of "shared logic" copied across multiple systems, extract it into a shared package, and have each system reference it. Then, manage the dependency versions for that shared package in a single location. This alone prevents the recurring mishap where "a fix was made but not reflected everywhere," while making cross-cutting dependency tracking slightly easier. By verifying the impact before expanding the scope incrementally, you can keep migration risk low.
If repository sprawl obscures your dependency landscape, vulnerability responses exhaust your team with audits, or copied shared logic is scattered across systems, please consult us via GleamHub's contact page. We will review your current repository structure and dependency graphs, partnering with you to design a phased consolidation that cuts off dependency drift without stopping your systems.








