Skip to content

What Problem Do Microfrontends Actually Solve?

The most common argument for microfrontends sounds plausible at first:

Our frontend application is large, so we need microfrontends.

But “large” does not yet describe an architectural problem.

A large application can be cleanly modularized along domain boundaries. One team may be able to understand it, build it quickly, test it reliably, and deliver it economically as a single unit. Conversely, an application can consist of one host and ten remotes and still require a shared release train, several approvals, and coordination with three other teams for every change.

The number of files is therefore rarely the deciding factor. Bundle size and the duration of a full build are initially just symptoms as well. The more important question is:

Which changes should teams be able to make without coordinating the entire product and several other teams?

Microfrontends do not primarily address an excess of frontend code. Their strategic value emerges where organizational and technical dependencies can be shaped so that teams can understand, change, test, release, and operate domain areas more independently.

That is a capability, not a guarantee.

Splitting an application technically into a host and remotes creates neither domain ownership nor independent teams. At first, it merely creates several technical units. Whether those units result in genuine autonomy or merely distributed coupling is decided by the architecture.

When people discuss microfrontends, organizational and technical independence are often mixed together. The two are related, but they are not the same.

From an organizational perspective, microfrontends can provide a structure in which a team owns a domain area. That team has its own priorities, makes release decisions, and is responsible for quality and operations. Different areas of the product can evolve at different speeds without every change having to follow a shared cadence.

The goal is more independent teams, not isolated teams.

Shared standards, platform decisions, and domain coordination remain necessary. Autonomy does not mean that nobody has to talk to anyone else. It means that not every local change triggers an organization-wide negotiation.

Technical independence, by contrast, describes concrete properties of a system:

  • its own build
  • focused tests
  • a separate deployment
  • its own data access
  • local UI and application state
  • explicit integration contracts
  • a targeted rollback
  • limited scopes of change and failure

Under suitable conditions, a remote can also be integrated into different hosts. That, however, is a separate capability and does not automatically follow from having a separate deployment.

Both dimensions have to align.

A team is not autonomous merely because its remote has its own pipeline. If every domain change still requires modifications to a central library, a new host version, and a second remote released in sync, the release has been split technically, but it has not become independent.

Conversely, organizational ownership remains ineffective when the responsible team does not technically own an area that it can change without intervention from other teams.

Organizational autonomy without technical decoupling remains an intention. Technical decoupling without ownership remains infrastructure.

Organizational and technical autonomy combine to enable independent change.

A Remote Does Not Create a Domain Boundary

Section titled “A Remote Does Not Create a Domain Boundary”

A remote can make a domain area of responsibility visible and technically separable. That is one of its most interesting properties.

The emphasis is on can.

A remote that is poorly divided along domain boundaries remains poorly divided even when it is built and delivered separately. It can use the same transport models as other remotes, access a global store, distribute domain rules through shared libraries, or depend on events whose senders and consumers nobody fully understands.

It may then have its own repository, build, or deployment URL. Its actual ability to change still depends on other areas.

A common misunderstanding is to equate the technical unit with the domain responsibility. The remote may be called billing, yet handle only a small part of billing. Important rules live in the shell, shared forms live in a shared library, and the approval logic lives in another remote. The name suggests ownership while the architecture prevents it.

This kind of ownership cannot be created through configuration.

The value of a microfrontend therefore does not lie in being small. It lies in changes within its boundary requiring as little approval as possible from outside that boundary.

Bounded Scopes of Change Instead of Trivial Applications

Section titled “Bounded Scopes of Change Instead of Trivial Applications”

The idea of bounded responsibility quickly creates a second misunderstanding: that a remote must be small, simple, and completely easy to understand.

That is not necessarily the case.

The calendar of a medical practice initially sounds like a manageable feature. In reality, it can represent a highly complex domain. It has to coordinate clinicians, rooms, and other resources. Appointment types can have different durations, preparation times, and dependencies. Recurring appointments intersect with blocked periods, parallel treatments, and conflict rules. Absences, substitutions, permissions, and last-minute changes add further complexity to the schedule.

That complexity does not disappear because the calendar is implemented as its own remote.

The calendar team may need to understand its domain in great depth. It has to know when two appointments may genuinely run in parallel, which resource must be reserved exclusively, and which change affects an entire recurring series. A clean boundary does not remove domain depth.

It can, however, limit the breadth of knowledge required.

To change the handling of a scheduling conflict, the team does not also have to understand the rules of billing, document management, patient records, and system administration. Those areas remain part of the same product, but they sit outside the immediate scope of change.

Microfrontends do not make complex domains simple. They can, however, prevent every change from requiring an understanding of the complexity of the entire product.

The medical practice calendar is deep in domain terms while remaining separated from other product areas.

The size of a remote therefore cannot be expressed meaningfully through lines of code, component count, or bundle size alone. A complex domain area can remain justified as an independent unit when its responsibility boundary is sound.

The decisive question is not: “Is the remote small enough?”

A more useful question is:

Which parts of the product does a team need to understand and coordinate in order to change this area safely?

In addition to organizational benefits, microfrontends can also provide concrete technical advantages.

When a remote forms its own scope of change, a local modification does not necessarily require the entire product landscape to be built and tested. Affected projects can be identified deliberately, builds can be focused, and tests can be assigned to a clear area of responsibility.

In a monorepo, affected strategies can support this isolation further. Regardless of the specific tooling, the fundamental advantage is the same: the technical feedback loop aligns more closely with the actual change.

This capability is not exclusive to microfrontends. A modular monolith can also use a clean project graph to build and test only what is affected. With microfrontends, that technical isolation can additionally result in independent delivery.

This can mean:

  • shorter build times
  • fewer tests for a particular change
  • faster local startup
  • clearer responsibility for failing tests
  • less unnecessary work in the CI pipeline

A smaller test surface must not lead to the conclusion that integration tests are no longer needed.

Fewer tests per change does not mean fewer kinds of tests.

A remote still needs tests for its own behavior. Depending on the architecture, contract tests, host integration, smoke tests, and tests of critical version combinations may also be required.

The tests do not disappear. They are distributed differently.

That distinction matters. In a favorable architecture, microfrontends reduce the number of tests directly affected by a change. At the same time, they create new integration surfaces that also need protection. Whether the overall test strategy becomes faster and more reliable depends on the boundaries and contracts of the system.

A Deployment Artifact Is Not Yet an Autonomous Deployment

Section titled “A Deployment Artifact Is Not Yet an Autonomous Deployment”

Independent deployments are among the strongest arguments for microfrontends.

A team can release a change without redeploying other areas of the product. A faulty release can be rolled back selectively. Different areas can follow different release frequencies. A rapidly evolving product area does not have to wait for another area that changes only a few times a year.

This becomes a real advantage only when the deployment can also be activated and operated independently.

A separate artifact is not enough.

If Remote A works only with a specific host version, requires a new shared library at the same time, and also assumes that Remote B has been released in exactly the same version, then several deployment artifacts exist, but the release is still shared.

The technical process has been distributed. The dependency between changes has remained.

Autonomous deployments therefore require controlled contracts and a deliberate compatibility strategy. Depending on the architecture, this may involve versioning, manifests, controlled activation, and defined rollback scenarios. The concrete technical implementation is a separate topic. For the fundamental distinction, the following is enough:

A deployment is not independent because it has its own pipeline. It is independent when it can be changed safely without a synchronized release of other areas.

A well-bounded remote can, under certain conditions, be integrated into multiple hosts.

Not every microfrontend has to work in multiple hosts. Where this capability is presented as a benefit, however, it has to be made real through explicit platform contracts and the absence of hidden shell dependencies.

This capability is particularly interesting when a domain area is needed in different products, tenant-specific solutions, or user interfaces. It requires the remote not to remain silently tied to one particular shell.

The platform context has to be passed explicitly. The remote should load its own domain data or at least receive it through a clear contract. Navigation and authentication need deliberate integration. Global styles and state must not be assumed accidentally.

As soon as a remote works only because the shell sets several global variables before startup, initializes a particular store, and emits a series of undocumented events, its technical reusability is largely theoretical.

Three properties should therefore be considered separately:

  • independently deployable
  • independently operable
  • integrable into different hosts

A remote can be deployed separately and still work only inside one particular shell. It can be embedded in multiple hosts while relying on a central backend process for its operation. Or it can be operated independently without ever having been intended for integration into more than one host.

These capabilities complement one another. They are not identical.

Clearer Boundaries Can Make Refactoring Easier

Section titled “Clearer Boundaries Can Make Refactoring Easier”

An often underestimated problem in large, tightly coupled systems is not only their objective complexity. It is the uncertainty surrounding the consequences of a change.

I do not know what else depends on this.

That sentence prevents more necessary refactorings than a lack of knowledge about design patterns.

When global state, shared models, and implicit side effects run through the system, even a local improvement becomes risky. Not because the change itself is particularly difficult, but because its blast radius is unknown.

A cleanly bounded remote can make that radius more visible. The team knows its contracts, has targeted tests, and can release or roll back a change separately. This does not make every refactoring safe automatically. But both the perceived and the actual risk can decrease.

The confidence to refactor does not simply come from having less code.

A small remote can be more tightly coupled through global stores, shared libraries, and unknown event consumers than a large, cleanly modularized area. Conversely, a substantial domain remote can remain easy to change when its boundaries are known and its dependencies explicit.

The confidence to refactor does not come from having little code. It comes from trusting the boundaries of the system.

That trust has to be earned technically. A separate folder or repository is not enough.

The properties discussed so far can support further use cases.

A legacy frontend can, for example, be modernized incrementally by introducing new or revised areas alongside the existing system in a controlled way. Product areas can evolve at different speeds. New capabilities can be integrated into existing hosts without rebuilding the entire interface.

The scope of failure can also be limited. A non-critical area does not necessarily have to make the entire product unusable. This does, however, require the shell and the integration architecture to handle failures deliberately. A dynamically loaded remote does not provide a reliable fallback by itself.

Investment can also become more targeted. A strategically important domain area can have its own roadmap, a specialized team, and an appropriate technical architecture without imposing the same decisions on the entire frontend immediately.

These possibilities are real. They do not arise merely from the existence of multiple deployments.

The same host-and-remote structure can lead either to autonomy or to distributed coupling.

What Microfrontends Do Not Provide Automatically

Section titled “What Microfrontends Do Not Provide Automatically”

Microfrontends create possibilities. They do not guarantee good architecture.

This becomes particularly clear with properties that are easily assumed in architecture diagrams.

A shared design system can support visual consistency by standardizing colors, typography, spacing, and components. It does not guarantee consistent interaction patterns.

Two remotes can use the same button component while validating forms differently, handling navigation differently, or presenting contradictory save behavior. Visual consistency and a consistent user experience are not the same thing.

UI and UX standards have to be designed deliberately as a platform capability.

Error handling does not automatically improve when an application is divided into multiple remotes.

One remote shows a toast, another opens a dialog, and a third silently writes a message to the console. Even if all three react to the error correctly from a technical perspective, they do not form a consistent product for the user.

Platform standards have to define which errors are handled locally, which information should be visible centrally, and what notifications should look like. A shared notification service can help. It does not replace the domain decision about which message is appropriate in which context.

An event bus provides a technical communication channel. It does not create good domain communication.

Global events can make dependencies more explicit when their contracts are clearly defined and their ownership is understandable. They can just as easily create an invisible execution graph in which nobody knows who reacts to which event.

A technical channel is not yet an architecture.

Microfrontends do not automatically improve browser performance.

Separate remotes can cause additional requests, duplicated dependencies, and multiple copies of framework runtimes. Initializing multiple applications, loading redundant styles, or performing uncoordinated data requests can also increase runtime costs.

Under suitable conditions, areas can be loaded selectively and changes can be isolated more effectively. Whether the result is faster or slower depends on the concrete integration.

A remote running under the same origin is not an isolated sandbox. A separate repository or deployment does not create its own security boundary in the browser. Authentication, authorization, and JavaScript executed in the same runtime therefore require a deliberate security architecture.

Multiple microfrontends can run perfectly well in front of a backend monolith.

That can be a useful transitional architecture or even a permanent solution. It does mean, however, that frontend autonomy and end-to-end autonomy can diverge. If every domain change still requires central backend approval, a substantial part of the dependency remains.

That is not necessarily a flaw. In this case, the achieved autonomy is limited to the frontend and should be described honestly as such.

Conversely, not every microfrontend requires its own microservice.

The backend structure should emerge from domain and operational requirements, not from a symmetrical architecture diagram.

Good Domain Boundaries and Good Code Quality

Section titled “Good Domain Boundaries and Good Code Quality”

Microfrontends do not create bounded contexts merely because several builds exist. They do not prevent god components, unclear responsibilities, or imperative chains of side effects.

Bad code can arise inside a remote just as easily as inside a monolith.

The difference is that its consequences can become more expensive through runtime integration, deployment, and cross-team contracts.

Microfrontends do not forgive bad architecture. They merely make its consequences more visible and more expensive.

A common expectation is that microfrontends make a large frontend simpler.

Locally, that can be true.

For a particular change, the relevant domain context may become smaller. Fewer teams may be directly affected. The build may cover fewer projects. Tests can be run more selectively. The blast radius becomes smaller and easier to assess.

Across the system, however, new complexity emerges:

  • integration contracts
  • versioning
  • runtime integration
  • platform standards
  • observability
  • release governance
  • security boundaries
  • compatibility management

Microfrontends do not eliminate complexity. They redistribute it.

The decisive question is therefore not whether the system looks less complex after being divided.

What matters is whether the complexity moves to a place where the organization and the technology can manage it more effectively.

A platform team can, for example, solve runtime integration, shared standards, and observability centrally while product teams change their domain areas independently. That can be economically sensible when many teams need the same platform capabilities and genuine coordination costs decrease as a result.

The opposite can happen as well. A small organization builds an elaborate platform even though only one team works on the application. The new integration architecture then solves no real bottleneck and mainly creates additional operational and maintenance work.

Microfrontends are particularly plausible when several teams regularly work in parallel on the same product landscape and shared releases have become a genuine bottleneck.

They can also make sense when product areas change at different rates, domain responsibility boundaries are sound, or incremental modernization is required. Independently integrating individual areas into multiple hosts can also provide substantial value.

They are less plausible when only one team works on the application, everything is delivered together anyway, or the domain boundaries are so unclear that almost every change affects several remotes.

In such situations, a modular monolith can achieve the same goals with less integration overhead.

That is not a preliminary stage that should be left behind as quickly as possible. For many products, a well-structured modular monolith can be the more economical architecture. It can support domain boundaries, clear ownership, and focused tests without adding runtime versioning, distributed deployments, and compatibility management.

The relevant economic question is therefore not:

Can we split this application into microfrontends?

Technically, almost any application can somehow be split into multiple runtime units.

The more important question is:

Is the value of independent change greater than the cost of distributed integration?

That cost includes more than infrastructure. It also arises from additional contracts, platform work, operations, debugging, and the need to make multiple runtime units appear as one coherent product.

A sound decision therefore starts with the bottleneck.

If teams can barely deliver independently because of shared releases, unclear ownership, and product-wide test cycles, microfrontends can be an appropriate answer.

If the actual problem is poor modularization, missing tests, or unclear domain responsibilities, several remotes will not solve those problems. They will merely distribute them across several artifacts.

The value of a microfrontend does not lie in being smaller.

It lies in enabling a team to understand, change, test, release, and operate a domain area as independently as possible.

That area may be deep in domain terms and technically demanding. What matters is how many external dependencies have to be coordinated for a change and how clearly responsibility for the outcome is assigned.

Microfrontends can enable focused builds, targeted tests, different release cadences, and incremental modernization. They can make domain boundaries visible and give teams the confidence to carry out necessary refactorings.

They provide none of this automatically.

Whether a host and its remotes become independent scopes of change or a distributed monolith is not decided by Module Federation.

Architecture decides.