Back to Blog
micro-frontends
webpack
architecture
react

Building Micro Frontends with Webpack Module Federation

A hands-on look at building a micro frontend architecture with Webpack Module Federation, including the real trade-offs, benefits, and challenges I ran into.

February 20, 20248 min readBy Amaresh

Building Micro Frontends with Webpack Module Federation

As frontend applications grow, the pressure on a single codebase grows with them. More teams, more features, more release cycles, and more coordination overhead. At some point, the frontend starts feeling less like a product and more like a traffic jam.

That was the motivation behind exploring Micro Frontend Architecture in a more hands-on way.

In this post, I’m sharing what I learned while building a micro frontend application using Webpack Module Federation. This is not just a theory-first explanation. It comes from actually wiring separate applications together, dealing with runtime integration, and seeing where the architecture helps and where it gets complicated.

What is Micro Frontend Architecture?

Micro Frontend Architecture is an approach where a large frontend application is split into smaller, independent applications that come together to form a single experience.

Each micro frontend can:

  • Be developed independently
  • Be deployed independently
  • Be owned by different teams
  • Use different frameworks or libraries when needed

The idea is very similar to microservices on the backend. Instead of one large frontend codebase trying to do everything, we break it into smaller pieces with clearer boundaries.

The Project I Built

To understand this properly, I built a project focused on getting practical experience with micro frontends rather than just reading about them.

The application had 4 standalone modules, and each module was treated as its own application.

That setup helped me explore:

  • How a host application loads remote modules at runtime
  • How multiple applications can share dependencies safely
  • How independently built modules can still feel like one product
  • How communication and integration become more complex as boundaries increase

One of the most useful parts of this exercise was that it made the trade-offs very visible. Micro frontends sound attractive when you hear “independent teams” and “independent deployments,” but the real learning starts when you have to coordinate versions, styling, routing, and shared state across multiple apps.

What is Webpack Module Federation?

Webpack introduced Module Federation in version 5, and it changed how independently built frontend applications can work together.

Module Federation allows applications to:

  • Expose modules for other applications to consume
  • Load remote modules dynamically at runtime
  • Share common dependencies like react and react-dom

In practice, this means you can have a host application that loads pieces from remote applications only when needed.

Core Concepts

Host

The host is the main application responsible for loading remote modules.

Remote

A remote is an application that exposes components or modules for another application to consume.

You can think of the structure like this:

Host App
   |
   |---- Remote App 1
   |---- Remote App 2
   |---- Remote App 3
   |---- Remote App 4

This runtime loading model is what makes Module Federation powerful. The host doesn’t need all remote code bundled into it during build time.

Build-Time vs Runtime Integration

While working on this project, one distinction became especially important: build-time integration and runtime integration are very different architectural choices.

1. Build-Time Integration

In build-time integration, a shared frontend module is packaged and consumed like a normal dependency.

Typical flow:

App A publishes package

App B installs package

App B rebuilds

Pros

  • Easier to reason about
  • Works with standard tooling
  • Better static guarantees during development

Cons

  • Requires rebuilds when a dependency changes
  • Creates tighter coupling between applications
  • Does not give true independent deployment

2. Runtime Integration

Runtime integration loads remote modules when the application is already running. This is the model Module Federation enables.

Typical flow:

User opens Host App

Host loads remoteEntry.js

Remote components are resolved dynamically

Pros

  • Independent deployment becomes possible
  • Teams can release separately
  • Applications stay decoupled at build time

Cons

  • Configuration is more complex
  • Runtime failures become a real concern
  • Version compatibility must be managed carefully

This was one of the biggest practical takeaways for me: runtime flexibility is powerful, but it shifts some complexity from build time into integration time.

Why Micro Frontends Can Be Valuable

When the application is large and multiple teams are involved, micro frontends can create meaningful operational benefits.

Independent Development

Different teams can work on different parts of the product without constantly stepping into the same codebase.

Independent Deployment

A single module can be updated and deployed without forcing a full frontend release.

Technology Flexibility

Different modules can adopt different frameworks if there is a good reason for it.

Smaller, More Focused Codebases

Each module stays easier to understand, maintain, and evolve.

Better Scaling for Large Teams

As the organization grows, the architecture can align better with team ownership.

The Challenges I Ran Into

This project also made it clear that micro frontends are not automatically a better architecture. They solve some scaling problems, but they introduce a new class of integration problems.

1. Dependency Sharing

This is one of the first real issues you hit.

If multiple micro frontends load their own copies of shared libraries, you can end up with:

  • Larger bundles
  • Duplicate dependencies
  • Runtime inconsistencies
  • Framework-level issues, especially with React

That is why dependency sharing rules matter so much.

shared: {
  react: { singleton: true },
  'react-dom': { singleton: true }
}

Using shared singletons helped avoid multiple React instances and kept the runtime behavior predictable.

2. State Management

State sharing becomes much less straightforward once parts of the UI live in separate applications.

Approaches I evaluated conceptually include:

  • Shared global state
  • Event-based communication
  • URL-driven state

The main lesson here is that not all state should be shared. Over-sharing state between micro frontends can quickly create tight coupling again.

3. CSS Conflicts

When multiple apps render into the same experience, styling collisions become a real concern.

Two modules can easily define similar class names or make assumptions about global styles. Without clear boundaries, the UI becomes fragile.

Common ways to reduce this problem:

  • CSS Modules
  • Scoped styling
  • BEM-style naming
  • Strong design-system conventions

4. Global Namespace Problems

Micro frontends can accidentally compete in the global environment if they rely too much on shared globals.

That can lead to hard-to-debug issues, especially when multiple teams ship changes independently.

The safest approach is to avoid global coupling as much as possible.

5. Communication Between Micro Frontends

This is where the architecture becomes more interesting.

Modules often need to react to shared events such as:

  • Authentication updates
  • Cart changes
  • Theme changes
  • Navigation-related state

Some common patterns are:

  • Host-controlled props
  • Custom events
  • Shared state containers

The important part is not just choosing a communication strategy, but keeping it minimal and explicit.

6. Routing Coordination

Routing sounds simple until multiple micro frontends want partial ownership over navigation.

You have to define whether routing is:

  • Fully controlled by the host
  • Split across nested apps
  • Coordinated through a shared contract

Without that clarity, navigation can become inconsistent very quickly.

7. Performance

Micro frontends do not automatically improve performance. In some cases, they can make it worse if the integration is careless.

Important considerations include:

  • Lazy loading remote modules
  • Sharing dependencies properly
  • Avoiding unnecessary duplication
  • Providing good loading states

8. Testing Complexity

Testing becomes more involved because failures can happen at the contract boundary between apps, not just inside one codebase.

That means you need confidence at multiple levels:

  • Unit testing
  • Integration testing
  • End-to-end testing
  • Contract validation between host and remotes

Things That Are Often Overlooked

These are the areas I think are often under-discussed when people present micro frontends as a silver bullet.

Design Consistency

If each micro frontend evolves independently without shared design rules, the user experience starts to feel fragmented.

Version Compatibility

Independent deployments are useful, but they also mean versions can drift. Shared dependency strategy becomes a long-term architecture concern, not just a config detail.

CI/CD Strategy

Micro frontends work best when the delivery pipeline also supports the architecture. Independent modules need independent release workflows, but still require coordination when contracts change.

Monitoring and Observability

Once multiple apps participate in one user journey, debugging production issues gets harder. Logging, monitoring, and error tracking become even more important.

When Micro Frontends Make Sense

From what I learned, micro frontends are most useful when:

  • The application is large
  • Multiple teams own different domains
  • Independent deployment is important
  • Clear module boundaries already exist

For smaller products or early-stage applications, this architecture can be unnecessary overhead.

Final Thoughts

Building this project gave me a much better understanding of both the appeal and the complexity of micro frontends.

What I liked most was the modularity and the way Module Federation enables runtime composition. What stood out just as much, though, was how much discipline is required around dependency sharing, communication patterns, routing, styling, and release management.

Micro frontends are not just a frontend scaling pattern. They are an organizational and architectural decision.

Used in the right context, Webpack Module Federation can be a very effective way to compose independent frontend applications while still delivering a cohesive product experience.