Block, Inc. has described a large-scale migration from a polyrepo architecture to a monorepo across its Cash App and Square engineering organizations to address growing coordination and dependency management challenges across backend systems. The initiative consolidated approximately 450 JVM-based repositories into a single codebase to simplify cross-service development, improve dependency visibility, and reduce operational friction across distributed systems.
According to the Block engineering team, the monorepo now supports approximately 8,800 builds per week, with p90 CI times of around 10 minutes on a reliably green main branch.
Under the previous polyrepo model, services and shared libraries were maintained in separate repositories, allowing teams to operate independently while introducing increasing coordination complexity over time. The model led to dependency version drift, duplicated upgrade efforts, and an increased risk of runtime incompatibilities across JVM services, including classic diamond dependency surprises.
Gabor Pap, Senior Engineering Manager at Block, mentioned,
What started as a complex, large-scale migration became a step-change in developer experience: a modern, cohesive codebase with an optimized IDE workflow, dramatically faster CI, and a foundation built for long-term velocity. The impact went far beyond tooling.
In the polyrepo model, dependency mismatches and cross-repository changes often require coordinated deployments across teams. The monorepo enables atomic updates across services in a single commit, while resolving shared dependencies directly from source rather than through independently versioned internal libraries.
To support the scale, Block built a custom IntelliJ plugin that loads only the projects an engineer needs, adopted merge queues to keep main stable under high commit volume, and invested in shared Gradle plugins, dependency graph– based build scoping, and git performance tuning, including exploring sparse checkouts, as the repository grew.
InfoQ interviewed Yissachar Radcliffe about the migration.
InfoQ: What scaling or coordination challenges made the polyrepo model unsustainable, and what alternatives did you evaluate before deciding to migrate to a monorepo?
Yissachar Radcliffe: Dependency management in the polyrepo had become unmanageable. We were constantly dealing with breaking changes, which sometimes manifested as runtime failures. Trying to roll out a library or API change to downstream consumers often required a heroic effort. We explored alternatives that would keep us on the polyrepo model by enhancing protection against breaking changes, but ultimately determined that a monorepo would solve the problem better and more generally improve our developer experience.
InfoQ: How do you construct and use dependency graphs to scope builds, tests, and code changes efficiently across the monorepo?
Yissachar Radcliffe: We look at which files were modified in a PR and then check them against our project dependency graph to figure out which projects need to be built and how. Roughly speaking, we categorize changes into one of three categories: the change directly affects a project (e.g., a file change in the project itself), the change indirectly affects a project (e.g., a change in an upstream project that the project depends on), the change is a global change that should cause the entire monorepo to be built (certain core file changes). This categorization ensures that we build everything necessary to prevent breaking changes, while also allowing us to tweak what we build for each change type. For instance, for indirect changes, we are able to drop various CI checks that cannot possibly fail.
InfoQ: The custom IntelliJ plugin is a key part of the developer experience. How does it determine which projects to include or exclude for a workflow, and how do engineers override those defaults when needed?
Yissachar Radcliffe: Engineers specify which projects they are working on, and we only load those projects into IntelliJ. Behind the scenes, we dynamically swap project references with published JAR references for dependent projects. This keeps the IDE fast and manageable and avoids a slow Gradle configuration phase. There are open-source versions of this approach available at https://github.com/joshfriend/spotlight and https://github.com/block/artifact-swap.
InfoQ: As the monorepo scaled, how did you maintain clear ownership and service boundaries while optimizing CI/CD through techniques such as selective builds, caching, and change detection?
Yissachar Radcliffe: We use Block’s repo ownership tooling to define owners for each project. Teams are responsible for their project code, while the monorepo team owns general build tooling. We also developed a strong set of Gradle convention plugins defining common module types, such as proto modules, service modules, library modules, and more. These not only help keep our dependency graph manageable (e.g., a service module can't depend on another service module) but also allow us to easily roll out improvements to all projects.
InfoQ: Since moving to a monorepo, have AI-assisted development tools changed how engineers navigate or work with the codebase, and what new challenges have emerged at this scale?
Yissachar Radcliffe: The big change has been that the IDE has become less of a focus for us as many engineers incorporate AI-assisted tooling into their development workflows. Agents perform well in our monorepo due to having access to so much context, and our bet on standardization has paid off as we have well-paved paths for agents to follow. Our scaling challenges have largely remained the same as pre-AI (build performance, git scalability, etc.); we're just seeing a higher rate of code changes now.
InfoQ: Looking back, what were the most difficult or unexpected challenges during the migration, and under what conditions would you advise teams not to adopt a monorepo?
Yissachar Radcliffe: The migration took longer than originally planned due to the difficulty of maintaining our desired developer experience. We were constantly discovering new CI scalability challenges as the monorepo grew; these had to be dealt with before we could bring in more projects. Additionally, there were a number of polyrepo projects with extremely slow builds or very custom setups that required extensive effort to optimize before we could bring them in. While these cases were a small minority of the total project set, they consumed an inordinate amount of our attention.
Both monorepos and polyrepos require proper investment in platform teams in order to flourish, but of the two choices, monorepos really suffer under neglect. If you can't commit to properly funding a platform team to support a monorepo, you'll probably do better with a polyrepo where teams can improve their own codebases and won't be punished by poorly behaved sibling projects. Monorepos are also best for similarly shaped projects. If your projects are a mix of different languages, frameworks, and styles, a monorepo may not provide significant benefit and might not be worth the investment.