Skip to content

Monorepo or Multiple Repositories?

The idea initially appears consistent:

one team
→ one microfrontend
→ one repository
→ one pipeline
→ one release

If microfrontends are meant to create independent frontend areas, a shared repository seems to contradict that independence. After all, the source code lives in one place. Dependencies are visible. Teams can theoretically access the same files. Changes to central configuration may affect the entire workspace.

It is therefore easy to conclude that every remote needs its own repository.

Real products, however, offer an equally plausible alternative:

one monorepo
├── host
├── Remote A
├── Remote B
├── Remote C
├── shared platform libraries
└── separate builds and deployments

In this structure, the remotes can still be built, tested, published, and owned by different teams independently. A shared source location initially means only that the projects are managed in the same repository. It says nothing about whether they produce the same artifact or must be released together.

Conversely, multiple repositories do not automatically create genuine independence:

Repository A
Repository B
Repository C
but:
├── shared approval
├── central test environment
├── synchronized releases
├── manual contract migration
└── shared operations calendar

The source code has been separated. The change and release processes remain coupled.

The decisive question therefore shifts. Before deciding on the number of repositories, the meaning of their boundaries has to be understood:

Which boundary does a repository actually represent?

Microfrontends enable separate repositories. They do not require them.

Repository boundaries are not automatically deployment, domain, or organizational boundaries. A monorepo can support independent releases very well as long as deployables, ownership, and pipelines remain separate. Multiple repositories can strengthen autonomy, but they increase the cost of shared toolchains, local development, and cross-cutting changes.

The other half of the decision is organizational: a monorepo scales particularly well within shared governance. Multiple repositories often become useful where access rights, budget responsibility, release authority, and organizational control are genuinely separate.

Discussions about monorepos often treat several different boundaries as though they had to run through the same place:

Repository Boundary
Deployment Boundary
Team and Ownership Boundary
Domain Boundary

These boundaries can coincide. They do not have to.

The repository boundary determines, among other things:

  • which source code is versioned together,
  • which changes can be made atomically in one commit,
  • which toolchains and rules are available centrally,
  • which people have access to the same source space.

It therefore primarily describes a shared development and control space.

The deployment boundary determines:

  • which artifact is built independently,
  • which unit can be published separately,
  • which pipeline and runtime belong to a deployable,
  • which release does not necessarily have to pull another deployable along with it.

It runs where source code becomes an independently publishable and operable unit.

The team and ownership boundary determines:

  • who is responsible for changes,
  • who approves releases,
  • who responds to incidents,
  • who makes architecture and product decisions.

Ownership is therefore more than permission to modify files. It includes responsibility for behavior, quality, operations, and evolution.

The domain boundary determines:

  • which capability belongs to a product area,
  • which models and rules apply there,
  • which data and use cases belong to its responsibility.

It follows the product and its domain, not necessarily a directory structure.

One repository can contain several domain and technical boundaries. Multiple repositories can still form one tightly coupled unit of change.

The repository structure should support a desired working and governance structure. It does not create that structure automatically.

Four layered views show repository, deployment, ownership, and domain boundaries. One monorepo contains several independently released deployables assigned to different teams and business capabilities.

Microfrontends Do Not Require Separate Repositories

Section titled “Microfrontends Do Not Require Separate Repositories”

The technical strength of microfrontends lies in the ability to integrate and release separate frontend areas independently. This capability supports different organizational models:

  • one shared monorepo,
  • one repository per remote,
  • one repository per business unit,
  • several monorepos within one overall product,
  • external partner repositories,
  • hybrid combinations of these models.

The ability to distribute does not create an obligation to maximize distribution.

Technical autonomy means that separation is possible. It does not mean that every possible separation must be introduced immediately.

A remote should not have to remain in the same repository because its integration technically allows no alternative. Conversely, it does not have to be extracted artificially merely to justify calling it a microfrontend.

One repository per remote is not a natural consequence of microfrontend architecture. It is an organizational decision.

Especially within one shared product, several remotes can be separated by domain and released independently while their teams use the same platform standards, development tools, and quality rules. In this case, a monorepo can simplify collaboration without dissolving deployment boundaries.

Why a Monorepo Does Not Prevent Independent Releases

Section titled “Why a Monorepo Does Not Prevent Independent Releases”

A monorepo can contain several independent deployables:

workspace
├── host
├── todos-remote
├── tasks-remote
├── members-remote
├── platform-contracts
└── shared-tooling

Within this workspace, the remotes can still be separate release units:

todos-remote
├── own artifact
├── own pipeline
└── own deployment time
tasks-remote
├── own artifact
├── own pipeline
└── own deployment time

Repository and release exist on different levels.

One commit can change several projects without publishing all of them. Builds and deployments can target only the affected deployables.

A monorepo becomes a release monolith when processes and pipelines artificially treat every project as one unit.

This happens, for example, when every change always triggers a complete product build, every test has to run regardless of actual impact, or one central approval always publishes all deployables together. That coupling is not created by the shared repository root. It is created by the chosen build, test, and approval logic.

A monorepo does not prevent independent releases. Global build, test, and approval logic can.

A shared source location must not imply a shared release.

Independent releases do not mean that every change affects only one project. They mean that unaffected deployables do not have to be published for purely structural reasons.

The advantages of a monorepo are sometimes dismissed as personal convenience. In reality, they describe concrete development economics.

Dependencies between the host, remotes, platform contracts, and libraries can be analyzed centrally. Such a graph does not replace architecture, but it makes its technical consequences verifiable.

A change affecting several projects can be implemented in one commit:

one commit
├── platform contract
├── host adapter
├── Remote A
└── tests

The change remains visible as one coherent operation. A contract is not changed in one place while the required consumer update is forgotten in another repository.

Atomic does not automatically mean deployed at the same time. If artifacts can be released independently, the contract still has to tolerate the resulting version skew.

Linting, tests, TypeScript configuration, build tools, and quality rules can be maintained together. In practice, this shared toolchain often appears less impressive than its economic value actually is.

Several deployables can be started from one workspace and tested in their real integration. This is particularly valuable for flows involving the host, remotes, and shared platform services.

Renames, API adjustments, and structural changes can be searched, evaluated, and executed across the repository. Affected locations are not spread across several search spaces.

That does not mean every team should change foreign code at will. It initially means only that consequences are visible and changes can be handled as one technical operation.

Code, contracts, tests, and technical documentation live in one navigable space. New team members can understand product relationships more easily. Owners can see more quickly how a platform rule is actually used.

These advantages are not merely convenience. They reduce the real cost of coordinated change.

The strengths of a monorepo come from proximity. That same proximity creates its risks.

When everything is technically reachable, remotes can import internal implementations from other product areas. A needed type or helper function is only a few directories away. A short-term shortcut becomes a permanent dependency.

Proximity inside the repository must not be confused with permitted architectural coupling.

Similar code is centralized too quickly. Two local implementations become a shared library that is soon used by many remotes. A small adjustment then affects the entire product.

Shared libraries are not inherently wrong. They need a stable shared purpose and clear ownership. Similarity alone is not such a purpose.

A central toolchain simplifies maintenance, but it increases the impact of its changes. An upgrade to root configuration may affect large parts of the workspace even when the deployables are released independently.

The central toolchain is therefore a real platform responsibility.

A team can modify another team’s code directly because everything is reachable in the same pull request. Technically, this is efficient. Organizationally, it can undermine ownership.

The ability to make an atomic change must not mean that responsible teams are only informed afterward.

Broken root configuration or a global CI rule can block many deployables at once. An independent remote may then be unable to release even though its own code is unchanged and functional.

Changes to central libraries can trigger builds and tests for many remotes. This increases runtime, but it also reveals how much responsibility has been concentrated in one shared component.

A monorepo needs governance precisely because technical boundary crossings are so easy.

An affected strategy uses a project and dependency graph to derive which projects are impacted by a change:

Change
Project and Dependency Graph
affected projects
├── builds
├── tests
├── E2E scenarios
└── deployments

Nx Affected is a well-known example of this principle. The important point here is not the specific tool, but graph-based selection.

Unchanged projects that do not depend on a change do not necessarily have to be rebuilt or fully tested.

The quality of the result depends on a correctly modelled graph. Direct project dependencies can be captured. Hidden runtime coupling, shared external configuration, or implicit contracts may exist outside the visible graph.

Affected makes coupling visible. It does not remove it.

A simple example illustrates the difference:

Change to Remote A
└── only Remote A affected

A local change can have a small affected radius. The remote can be built, tested, and published selectively.

A change to a central library looks different:

Change to central platform library
├── host
├── Remote A
├── Remote B
└── Remote C affected

This result may reflect a legitimate central responsibility. An authentication context or a stable lifecycle contract may intentionally affect every integration partner.

It may also indicate an overly broad shared library that combines functions from otherwise independent domains.

A large affected radius is not a weakness of the monorepo. It is an architecture signal.

Why Multiple Repositories Make Autonomy More Visible

Section titled “Why Multiple Repositories Make Autonomy More Visible”

The idealized alternative physically separates the remotes:

Remote A Repository
├── own source code
├── own pipeline
├── own toolchain
└── own release
Remote B Repository
├── own source code
├── own pipeline
├── own toolchain
└── own release

This structure makes certain boundaries immediately visible.

Technical access boundaries are clearer. Teams can change toolchains independently. Pipelines and releases are separated organizationally. A broken repository does not automatically block all others. External organizations do not need access to the complete product source code.

Ownership is less easy to bypass casually because changing another remote requires a deliberate transition into another responsibility space.

Multiple repositories can protect autonomy because foreign changes cannot happen incidentally.

This physical separation is often called a polyrepo. It can be useful when the technical structure reflects genuinely separate responsibility.

It does not guarantee independent architecture.

Multiple repositories can still be coupled through synchronized releases, central approvals, a shared test environment, manual integration steps, or dependencies on artifacts that have not yet been published.

The source code is separate. The change mechanics are not.

Multiple repositories often create organizational calm. Technically and operationally, however, they are not free.

Repositories can use different versions of frameworks, build tools, linting, and tests. This freedom may be desirable, for example when lifecycles differ significantly.

It can also create maintenance cost: security fixes, quality rules, and knowledge about build and test systems are distributed across several variants.

Each repository may need its own form of:

  • CI configuration,
  • dependency updates,
  • quality rules,
  • release automation,
  • local startup instructions,
  • security and compliance configuration.

Central templates can reduce this repetition. They also introduce another shared platform dependency that must be versioned and maintained.

For product-wide flows, several repositories must be checked out, started, and combined in compatible versions. Not every team needs the complete product all the time. As soon as an integration defect has to be investigated, however, the distributed structure becomes noticeable.

Contracts, implementations, tests, and responsible teams are distributed across several locations. Global search is replaced by catalogs, documentation, and package registries.

That can work well. It requires deliberately maintained navigation and information structures.

A shared change requires several pull requests, versions, and coordinated rollouts. The technical separation makes visible that several areas of responsibility are involved. At the same time, operational effort increases.

Consumers and providers cannot be switched completely in one atomic commit. Transitional compatibility becomes necessary. Old and new contract variants have to coexist temporarily.

Organizational separation does not remove coordination. It moves coordination from the repository into contracts, versions, and release processes.

Multiple repositories make coupling more visible. They do not automatically make it smaller.

A central trade-off between a monorepo and multiple repositories lies in the mechanics of shared change.

one commit
├── change contract
├── update provider
├── update consumer
└── update tests

Such a change is easy to coordinate. The complete context remains visible. Errors in the shared adjustment are detected early.

Atomicity carries a risk, however: it can hide the fact that several independently owned deployables are affected.

If the change only works after all participants have been released at the same time, release coupling exists despite the shared commit. The monorepo makes implementation convenient, but it does not solve differing deployment schedules.

Independently released deployables inside a monorepo also need compatible transitions when their releases can occur at different times.

Compatible Migration Across Multiple Repositories

Section titled “Compatible Migration Across Multiple Repositories”

With separate repositories, the transition usually becomes more explicit:

1. Provider extends the contract compatibly.
2. A new contract version is published.
3. Consumers migrate independently.
4. Old and new variants coexist temporarily.
5. The old variant is removed later.

This approach supports independent schedules. Consumers do not have to release simultaneously. Organizational autonomy is taken seriously at the technical level.

The price is additional transition logic, versioning, longer migration phases, and greater coordination effort.

A monorepo makes coordinated change cheap. Multiple repositories more often force compatible change.

Separate repositories make independent change more expensive, but often more honest as well.

This is not an argument against atomic changes. They are valuable as long as they are not confused with a mandatory shared deployment.

On the left, a contract, provider, consumer, and tests are changed atomically in one monorepo. On the right, a timeline shows how a contract is extended compatibly and adopted gradually by several consumer repositories.

The repository decision is often treated as a question of technical scale. In many products, governance is the more important criterion.

A monorepo often fits a structure like this:

shared product
├── shared governance
├── shared technical leadership
├── shared access rules
├── shared quality standards
├── similar toolchains
└── aligned platform responsibility

Under these conditions, there is a shared interest in maintaining technical rules centrally, keeping dependencies visible, and implementing coordinated changes efficiently.

This does not mean every team needs the same release date or the same domain priorities. It means that a shared control and development space is fundamentally desired.

A monorepo optimizes collaboration within shared governance.

Shared governance has to be concrete. It includes responsibility for root configuration, platform libraries, architecture rules, central pipelines, and cross-cutting quality standards.

A monorepo pays with governance.

Without that governance, the shared workspace quickly becomes a place where everyone can change everything but nobody owns the consequences of central decisions.

Globally Distributed Does Not Mean Organizationally Separate

Section titled “Globally Distributed Does Not Mean Organizationally Separate”

Geographic distance is not a repository boundary.

A product can be distributed across Berlin, Munich, New York, and Singapore while still operating under shared governance. The teams may use the same access rules, architecture standards, product goals, and platform ownership.

In such an environment, a monorepo can offset physical distance through a shared technical context. Dependencies, contracts, and quality rules remain visible.

Conversely, two teams in the same building may be completely separate organizationally. If they have different budgets, approvals, access rights, and responsibility models, their physical proximity is largely irrelevant to the repository decision.

The relevant distance is not geographic. It is organizational.

Multiple Companies and Business Units Change the Decision

Section titled “Multiple Companies and Business Units Change the Decision”

The situation changes when several organizationally independent units contribute to one overall product:

shared product
├── Business Unit A
├── Business Unit B
├── subsidiary
├── external supplier
└── partner company

These units may differ in access rights, confidentiality, budget responsibility, personnel responsibility, release approval, compliance, operating models, priorities, lifecycles, liability, and support.

A monorepo would still be technically possible. Organizationally, however, it would become a shared control room. Questions such as these would have to be answered continuously:

  • Who may read which area?
  • Who may change global rules?
  • Who owns central CI?
  • Who decides on toolchain upgrades?
  • Who repairs a broken main pipeline?
  • Who may approve another product area?

These questions are solvable. Maintaining those solutions may cost more than the shared source space provides in return.

A monorepo can scale extremely well within shared governance. Across governance boundaries, the same centralization can become a source of conflict.

The further ownership, access rights, and release responsibility diverge, the less a shared repository root should be a prerequisite.

Separate repositories can then protect organizational autonomy:

Organization A
├── owns Repository A
├── owns Pipeline A
├── owns Remote A
└── releases Remote A
Organization B
├── owns Repository B
├── owns Pipeline B
├── owns Remote B
└── releases Remote B

One organization does not need complete access to another organization’s source code. Toolchain decisions can be made locally. A pipeline failure does not automatically block every participant. Release approvals remain inside the responsible organization. Contractual and regulatory boundaries can be represented technically.

Multiple repositories are not necessarily technically simpler here. They can be organizationally calmer.

A monorepo optimizes collaboration within shared governance. Multiple repositories can protect autonomy across governance boundaries.

On the left, geographically distributed teams work under shared governance in one monorepo. On the right, several business units, partners, and suppliers manage their own repositories or monorepos. A neutral transition area shows a possible hybrid model.

The repository question does not even have to be answered uniformly for the entire product.

One possible model looks like this:

Overall Product
├── BU A Monorepo
│ ├── Remote A1
│ ├── Remote A2
│ └── API A
├── BU B Monorepo
│ ├── Remote B1
│ └── Remote B2
├── Partner Repository
│ └── Remote C
└── versioned platform contracts

Within one business unit, several related remotes, APIs, and libraries can live in a monorepo. They benefit from a shared toolchain, discoverability, and atomic changes.

Other business units, companies, or suppliers can own separate repositories or monorepos. They publish their deployables within their own governance and integrate through versioned platform contracts.

Those contracts should remain limited to what is actually required, for example:

  • mounting and lifecycle contract,
  • authentication context,
  • navigation,
  • design system or tokens,
  • observability,
  • published API and event contracts.

Repository structure does not have to mirror the technical remote structure one to one.

One repository per governance space may be more useful than one repository per remote.

A hybrid model is not a universal best practice. It shows that a remote is a deployment and integration decision, while a repository also structures collaboration, access, and control.

A monorepo does not prevent clear ownership. It does require ownership to be visible and verifiable.

Possible mechanisms include:

  • code ownership,
  • project tags and module boundaries,
  • restricted imports,
  • separate pipelines,
  • separate release permissions,
  • named owners,
  • architecture tests,
  • different deployment targets.

These mechanisms do not replace collaboration. They prevent the shared source space from being treated as an invitation to cross boundaries arbitrarily.

Ownership that exists only in an organizational chart is weak. Ownership enforced only through separate repositories can be unnecessarily expensive.

The appropriate strength often lies between those extremes:

shared workspace
+
visible and verifiable boundaries
+
separate deployments
+
clear owners

A monorepo is particularly plausible when governance is shared, coordinated changes are common, toolchains are similar, and platform contracts are maintained regularly. Shared local development, central discoverability, and manageable access rights also support it.

The prerequisite remains that deployments are separate despite the shared source location and that module and ownership boundaries actually work.

Multiple repositories are particularly plausible when different companies or contractual partners are involved, business units have genuine autonomy, access rights differ significantly, or separate compliance and approval processes apply.

Significantly different lifecycles, independent funding, very different toolchains, few shared atomic changes, or required confidentiality can also justify a repository boundary.

A repository boundary becomes particularly useful when it represents a real governance, trust, or access boundary.

The choice between a monorepo and multiple repositories is not a matter of faith. The models have different cost profiles.

Monorepo
Strengths
├── atomic changes
├── shared toolchain
├── visible graph
├── simple discoverability
└── efficient local development
Costs
├── governance
├── module boundaries
├── central toolchain decisions
├── potentially large affected sets
└── protection against incidental coupling
Multiple Repositories
Strengths
├── clear access boundaries
├── autonomous toolchains
├── separate pipelines
├── organizational isolation
└── visible ownership
Costs
├── cross-repository coordination
├── version management
├── duplicated automation
├── more difficult local integration
└── compatible migrations

A monorepo pays with governance. Multiple repositories pay with coordination.

A monorepo can simplify a product with several independently released remotes considerably. That proximity still requires clear ownership, effective module boundaries, and separate release processes.

Multiple repositories become particularly useful where governance, access rights, companies, or release responsibilities are genuinely separate. In those cases, organizational autonomy may matter more than the efficiency of shared changes.

Repository boundaries are not deployment boundaries. Affected makes coupling visible, but does not remove it. The repository structure should represent the boundary within which shared change and shared control are genuinely desired.

The repository does not decide whether a release is independent. It decides how expensive shared change and organizational autonomy become.