← Back to Blog RSS

What Is a Monorepo? Architecture, Benefits, and How to Scale Yours

Monorepos Infrastructure Terraform OpenTofu DevOps

A monorepo is more than a storage decision. It's an architectural choice that shapes how teams collaborate, automate, and ship. For infrastructure-as-code teams in particular, getting it right determines whether your pipeline stays fast or grinds to a halt.

TL;DR
$ cat what-is-a-monorepo.tldr
• A monorepo stores multiple projects or services in a single version-controlled repository, instead of splitting them across many separate repos.
• Monorepo architecture brings shared visibility, unified tooling, and easier cross-project refactoring, but introduces challenges around CI performance and access control at scale.
• Infrastructure-as-code teams face unique monorepo challenges, because every change carries real-world consequences and blast radius is a consideration.

Most developers have worked in a repository they eventually outgrew. Sometimes it's a sprawling single repo that became slow and chaotic. Sometimes it's a constellation of separate repositories where frontend, backend, shared library, infrastructure code, and deployment scripts drift at different speeds, and one change becomes a week of coordination.

A monorepo is the software development strategy many teams reach for when that pain becomes obvious.

It stores multiple projects or services in a single version-controlled repository, rather than splitting them across multiple repositories, and can bring shared visibility, simplified dependency management, code sharing, easier refactoring, and better knowledge sharing.

However, it also changes how teams manage dependencies, run automated tests, enforce repository boundaries, and reason about the entire codebase.

What is a monorepo?

A monorepo, sometimes called a monolithic repository, is a single repository that contains the source code for multiple projects, services, shared libraries, tools, or teams. The opposite model is a polyrepo, where each project has its own repository, usually with its own CI/CD pipeline, dependency management, permissions, and release process.

Mono refers to the repository, not the software architecture. A monorepo can contain a monolith, but it can also contain dozens of independently deployable services, libraries written in multiple programming languages, build tool configuration, test harnesses, and infrastructure code.

A practical monorepo setup might place:

Monorepos are common. Google has published work on Piper as a common source of truth for tens of thousands of developers, Meta's engineering teams work in a large monorepo with a single main branch, and Microsoft described moving the Windows codebase, about 3.5 million files and roughly 300GB, from a Git repo, into a large Git based system.

Monorepo vs. polyrepo

A polyrepo gives each project autonomy over its build system, permissions, dependency management, and quality assurance workflow. This model works well when projects have distinct compliance requirements, separate release schedules, or ownership boundaries that make shared source code inappropriate.

A monorepo centralizes the work. Related projects live in the same repo, so a change to a shared library and every dependent application can land in one commit, reviewers can see the full context, and teams can maintain consistency across formatting, test conventions, and build artifacts.

The cost is discipline. Without affected-change detection, remote caching, incremental builds, and ownership policies, a monorepo can stop feeling collaborative and start feeling like a shared bottleneck, where every developer waits for unrelated projects to finish building.

Area Monorepo Polyrepo
Code location Multiple projects in one repository Each project is in its own repository
Collaboration Easier visibility and code sharing Stronger separation between teams
Dependency management Shared dependencies Dependencies managed per repo
CI/CD Unified pipelines that should run only what has changed Separate pipelines per repository
Access control Needs policies inside the same repository Permissions map to repository boundaries
Refactoring Atomic commits across multiple services Coordination across multiple repos
Best fit Related projects with mature tooling Unrelated projects or strict isolation needs

Neither model is universally better, the choice depends on how related the projects are, how often different teams change common code together, whether repository boundaries are a security requirement, and how mature the monorepo tools are.

What is monorepo architecture?

Monorepo architecture is the internal shape of the repo, the conventions that determine where components reside, how sub-projects depend on each other, how the build system discovers work, and how teams prevent accidental coupling.

Some teams use a flat layout, where projects sit at the root.

Others group by team or domain, so payments, platform, data, and security have scoped directories that map to ownership.

Workspace-based layouts (common with Nx, Turborepo, Yarn Workspaces, and pnpm) separate applications from packages and libraries, then use a dependency graph to understand code changes.

A practical monorepo usually contains multiple applications and libraries in one Git repository, with tooling that makes shared code explicit, allows atomic changes across project boundaries, keeps dependencies consistent, runs commands only against affected projects, and uses remote caching so repeated work does not punish every developer.

A simple monorepo structure might look like this:

repo/
  apps/
    web/
    api/
  packages/
    ui/
    config/
  libs/
    core/
    auth/
  infra/
    modules/
    environments/
  tools/
    ci/

Code organization becomes policy, so the shape of the repository has to make ownership, dependencies, and shared boundaries obvious.

If apps/api imports private internals from apps/web, the monorepo structure is lying. A well-structured monorepo makes shared code explicit, keeps common code in a shared library, defines ownership at the directory or stack level, and lets CI answer only what changed and what depends on it.

The key characteristics of a well-structured monorepo

A healthy monorepo has consistent tooling across projects, a clear dependency graph between internal packages, shared linting and formatting standards, and CI that understands affected projects. It also has social boundaries, because ownership, review status, and team boundaries must stay visible.

That distinction separates a monorepo from code colocation. Putting multiple services in the same repository is easy. Keeping large monorepos fast, understandable, and safe is what takes work.

The benefits of a monorepo

The main value of a monorepo becomes apparent when a change crosses project boundaries.

In a polyrepo, updating an API type might require one pull request in the backend, another in the frontend, a version bump in a shared package, and careful sequencing so the main branch is never broken. In a monorepo, the same change can land atomically, with automated tests proving that affected projects still work.

Large-scale refactoring becomes more realistic, too. When the entire codebase is visible, teams can:

A monorepo also gives platform teams one place to encode best practices. Formatting, security scanning, task orchestration, build artifacts, quality assurance gates, and release workflows can be maintained consistently.

In mature setups, remote caching and incremental builds let work already completed on one developer's machine or CI runner be reused across multiple machines.

The challenges of a monorepo

There is a predictable failure mode. The repo grows, large files accumulate, every pull request triggers too much work, and CI/CD becomes the tax every developer pays for everyone else's code.

The main branch gets more fragile, and access control becomes harder because Git repository permissions are usually blunt instruments. Monorepo tools become necessary rather than optional.

A serious monorepo needs:

Large monorepos need branching models that respect scale, because full-repo branching can become expensive, while directory-level workflows can preserve team ownership without forcing every team to coordinate through the same release path.

Onboarding friction is another cost. New developers have to understand the monorepo structure, build system, local commands, ownership rules, and CI behavior before they can safely change code.

Monorepos and infrastructure as code

Monorepos get more dangerous when infrastructure as code enters the same repository. Terraform and OpenTofu configurations are often split across modules, environments, stacks, and shared components. Those components benefit from the same monorepo approach as application code, as modules can be reused, environment differences are visible, and infrastructure changes can be reviewed alongside the services they support.

But IaC changes are not ordinary application changes. A broken unit test fails a build. A mistaken apply can change networking, destroy a database, rotate credentials, or modify production access. The standard monorepo instinct, run everything on every pull request, is slow for IaC, and can be expensive, noisy, and unsafe.

The key concept to keep in mind is blast radius.

In a large IaC monorepo, a pull request that touches /infra/networking should not automatically plan every environment, every module, and every stack. It should identify the affected stacks, understand dependencies, run the right Terraform or OpenTofu plans, and show reviewers exactly what will change before anything is applied.

For IaC teams, the useful question is not whether a pull request changed infrastructure code, but which stacks it affects, what depends on those stacks, what order the work should run in, and what reviewers need to see before anything is applied.

Stategraph is built around that model, so Terraform and OpenTofu workflows can follow the infrastructure graph instead of treating the repository as one flat pile of files.

Why affected-change detection matters for IaC

Running terraform plan across every module on every PR looks thorough, but it burns CI minutes, creates review noise, and trains developers to ignore output because too much of it is unrelated. A better model is to understand the infrastructure graph well enough to run only what is affected, then run those plans in the right order.

General-purpose monorepo tools are good at application dependency graphs, package builds, and test selection. Most do not understand Terraform state, OpenTofu workflows, workspace boundaries, module references, provider behavior, or the operational meaning of an apply.

IaC needs monorepo intelligence, but it also needs infrastructure intelligence.

Managing a monorepo at scale with Stategraph

Stategraph is built for Terraform and OpenTofu workflows inside large repositories where speed, reviewability, and safety have to coexist. You can easily understand which stacks are affected by a change, how those stacks depend on each other, and which operations can safely run concurrently.

The naive alternative is either over-execution or under-protection. Stategraph is built around graph-aware execution, resource-level locking, multi-state operations, and blast radius analysis because an IaC monorepo needs not only file-change detection. It needs to understand the infrastructure graph, especially when one repository contains many environments, stacks, and teams.

Large IaC monorepos contain shared modules, layered dependencies, team ownership boundaries, and apply rules that differ by environment. Stategraph handles that with tag-based configuration, stack-level access control, smart locking, layered runs, and module indexing, so changes trigger the right infrastructure workflows instead of turning every pull request into a full-repo event.

Stategraph keeps large IaC monorepos safe by locking only the stacks that need locking, showing reviewers the exact plan in the PR, and giving teams stack-level ownership without opening up the entire repository.

A monorepo can merely store infrastructure, or it can safely operate it. The first version is a storage decision. The second is an architectural choice backed by tooling that understands the consequences of code changes.

Conclusion

A monorepo is a single repo containing multiple projects, but the value comes from the workflow around it.

Good monorepo architecture:

For application teams, that usually means better code sharing, easier refactoring, simplified dependency management, and improved collaboration across services. For infrastructure-as-code teams, it also means blast radius control, safe plans, ordered applies, and policies that reflect the fact that code can change real infrastructure.

If your team is exploring one repository for apps, modules, environments, and shared infrastructure, ask yourselves if your tooling can keep the monorepo honest as it grows.

Try Stategraph free to see how graph-aware Terraform and OpenTofu workflows keep a monorepo fast, reviewable, and safe when it becomes your production control plane.

Monorepo FAQs

What is the difference between a monorepo and a monolith?

A monorepo is a repository strategy. A monolith is an application architecture. A monorepo can contain many independently deployed services, while a monolith is usually one application deployed as one unit.

Is a monorepo good for small teams?

Yes, when the projects are related, and the team benefits from code sharing, shared dependencies, and one CI/CD workflow. For unrelated projects, separate repositories may stay simpler.

What tools are used to manage monorepos?

Common monorepo tools include Nx, Turborepo, Bazel, Yarn Workspaces, pnpm, and language-specific build systems. IaC teams also need Stategraph for Terraform and OpenTofu behavior.

How do you handle CI performance in a large monorepo?

Use affected-change detection, incremental builds, remote caching, task orchestration, and clear dependency rules. The goal is to run only what a change can affect.

What is monorepo architecture in the context of infrastructure as code?

In IaC, a monorepo is the structure of modules, environments, stacks, shared components, and policies inside the same repository, plus the workflow that maps a change to the exact plans and applies it affects.