Module Federation Deep Dive for Micro Frontends
Understand webpack Module Federation from fundamentals to production architecture, including host, remote, remoteEntry.js, exposes, shared dependencies, singleton React, runtime loading, deployment, and failure handling.
Module Federation is one of the most popular ways to build micro frontends in modern JavaScript applications.
It allows one frontend application to load code from another frontend application at runtime.
That one idea unlocks a powerful architecture:
Different teams
Different codebases
Different builds
Different deployments
One composed user experienceBut Module Federation is also easy to misunderstand.
It is not just a way to import components from another app.
It is a runtime architecture pattern that affects deployment, dependency sharing, versioning, testing, rollback, and observability.
This guide explains Module Federation from beginner level to production architect level.
1. What Is Module Federation?
Module Federation is a webpack 5 feature that allows multiple independently built applications to share and consume code at runtime.
In simple words:
One application can expose code, and another application can load that code when needed.
Example:
Product App exposes ProductList
Shell App loads ProductList at runtimeThis is useful for micro frontends because the shell app does not need to bundle every feature during its own build.
Instead, each remote app can be built and deployed independently.
2. Why Module Federation Matters
Before Module Federation, frontend applications usually shared code in these ways:
npm packages
monorepo libraries
script tags
iframes
build-time importsThese approaches work, but they have limitations.
| Approach | Limitation |
|---|---|
| npm package | Requires rebuilding consumers after package updates |
| Monorepo library | Often still tied to one build/release process |
| Script tag | Harder dependency and type management |
| iframe | Strong isolation but poor UX integration |
| Build-time import | No true independent runtime deployment |
Module Federation solves a specific problem:
How can one app consume another app’s code without rebuilding itself every time?
That is why it is powerful for micro frontends.
3. Core Mental Model
Think of Module Federation like this:
Remote App
exposes something
Host App
consumes that exposed thingExample:
cartApp exposes CartPage
shellApp consumes CartPageArchitecture:
┌────────────────────┐
│ Shell App │
│ Host │
└─────────┬──────────┘
│ loads at runtime
▼
┌────────────────────┐
│ Cart App │
│ Remote │
│ exposes CartPage │
└────────────────────┘The shell does not directly own the cart code.
The cart team can build and deploy the cart remote independently.
4. Important Terms
| Term | Meaning |
|---|---|
| Host | Application that consumes remote modules |
| Remote | Application that exposes modules |
| Exposes | Modules/components made available by a remote |
| Remotes | Remote applications configured inside the host |
| remoteEntry.js | Runtime manifest used by host to discover and load remote modules |
| Shared dependencies | Libraries shared between host and remote |
| Singleton | Shared dependency loaded as one instance |
| Eager loading | Loads dependency upfront |
| Lazy loading | Loads remote only when needed |
5. Host Application
The host is usually the shell app.
It owns:
- Global layout
- Navigation
- Top-level routes
- Authentication bootstrap
- Remote loading
- Fallback UI
- Error boundaries
Example:
Shell App
├── Header
├── Navigation
├── Auth Guard
├── Route Config
└── Remote LoaderThe host consumes modules from remote apps.
Example:
/products → load productApp/ProductList
/cart → load cartApp/CartPage
/checkout → load checkoutApp/CheckoutPageThe host should coordinate composition. It should not become a place where every remote’s business logic is dumped.
The host should own composition concerns, not domain business logic.
6. Remote Application
The remote is an independently built application that exposes modules.
Example:
Product Remote
├── ProductListPage
├── ProductFilters
├── ProductCard
└── Product API clientThe remote may expose:
- Page components
- Widgets
- Feature modules
- Route configs
- Utility modules
Example:
productApp exposes:
- ProductListPage
- ProductDetailsPage
- ProductRecommendationsWidgetIn a clean architecture, a remote owns its business domain.
The product remote should own product listing logic. The cart remote should own cart logic. The checkout remote should own checkout logic.
7. What Is remoteEntry.js?
remoteEntry.js is the runtime entry file generated by the remote application.
It acts like a manifest that tells the host:
- What modules are exposed
- Where chunks can be loaded from
- How dependencies should be resolved
- How runtime loading should happen
Runtime flow:
Shell App
│
│ fetches remoteEntry.js
▼
Remote container initialized
│
│ resolves exposed module
▼
Remote chunks loaded
│
▼
Remote component renderedWithout remoteEntry.js, the host does not know how to load the remote.
8. Runtime Loading Flow
When a user visits a route, this is what can happen:
User opens /cart
│
▼
Shell app loads
│
▼
Shell checks route configuration
│
▼
Shell identifies cartApp remote
│
▼
Shell fetches cart remoteEntry.js
│
▼
Shell loads exposed CartPage module
│
▼
Cart remote chunks load
│
▼
CartPage renders inside shell
│
▼
Cart API fetches cart data
│
▼
Cart UI appearsThis is runtime composition. The cart app can be deployed separately from the shell.
9. Build-Time Import vs Runtime Federation
This distinction is very important.
Build-Time Import
Shell imports ProductList during build
Shell bundle contains ProductList
Changing ProductList requires shell rebuildExample:
import { ProductList } from "@company/product";Runtime Federation
Shell loads ProductList at runtime
ProductList comes from product remote
Product remote can deploy independentlyConceptually:
Build-time import = coupled at build time. Runtime federation = connected at runtime.
Comparison:
| Area | Build-Time Import | Runtime Federation |
|---|---|---|
| Deployment | Consumer rebuild needed | Remote can deploy independently |
| Runtime risk | Lower | Higher |
| Simplicity | Simpler | More complex |
| Team autonomy | Lower | Higher |
| Version control | Package version | Runtime manifest/version strategy |
10. Exposes
exposes define what a remote makes available to other apps.
Example:
cartApp exposes:
./CartPage
./CartDrawer
./CartSummaryThe host can then consume these exposed modules.
Good exposes are stable and intentional. Bad exposes leak internal implementation details.
| Good Exposes Practice | Bad Exposes Practice |
|---|---|
| Expose CartPage | Expose internal reducer |
| Expose CartWidget | Expose random utility |
| Expose route config | Expose private component |
| Expose API implementation details |
Expose stable public contracts, not internal implementation details.
11. Remotes
The host configures which remotes it can load.
Example conceptual mapping:
productApp → https://cdn.company.com/product/remoteEntry.js
cartApp → https://cdn.company.com/cart/remoteEntry.js
checkoutApp → https://cdn.company.com/checkout/remoteEntry.jsThe shell uses this mapping to know where to fetch each remote.
In production, this mapping may come from:
- Static config
- Environment variables
- Remote manifest service
- Feature flag service
- Deployment registry
The more dynamic the setup, the more governance you need.
12. Shared Dependencies
Shared dependencies are libraries used by both host and remotes.
Examples:
- React
- React DOM
- Design system
- Router package
- Analytics SDK
- Auth SDK
- Utility libraries
Without proper sharing, each remote may load its own copy.
That can cause: large bundle size, duplicate React instances, hook errors, inconsistent state, runtime crashes, and version conflicts.
Shared dependency management is one of the most important production concerns in Module Federation.
13. Singleton Dependencies
A singleton dependency is loaded only once and shared across host and remotes.
React is the classic example.
Why? Because multiple React instances can cause serious issues, especially with hooks and context.
Shell uses React instance A. Remote uses React instance B. Shared context or hooks behave unexpectedly.
Recommended config list:
- React → singleton
- React DOM → singleton
- Design system runtime → often singleton
- Auth SDK → often singleton
- Analytics SDK → depends on architecture
But do not mark everything as singleton blindly. Overusing singleton dependencies creates hidden coupling.
14. Dependency Sharing Strategy
| Dependency Type | Recommendation |
|---|---|
| React / React DOM | Share as singleton |
| Design system | Share with strict versioning |
| Router | Be careful; routing ownership matters |
| Utility functions | Usually avoid runtime sharing unless stable |
| API clients | Keep domain-owned |
| Business logic | Do not share through federation casually |
| State stores | Avoid global shared state unless required |
Strong rules to enforce:
- Share platform-level dependencies.
- Keep business logic inside the owning domain.
Bad architecture coupling examples:
- Cart remote imports product business logic from product remote.
- Checkout remote depends on cart internal reducer.
- Shell imports internal functions from every remote.
This creates distributed coupling.
15. Version Mismatch Problems
Version mismatch is a common production issue.
Example: Shell expects productApp/ProductList v2 props, but product remote deploys ProductList v3 with breaking props, causing the shell to crash at runtime.
Possible mismatch issues:
- Breaking prop changes
- Changed event payloads
- Missing exposed module
- Different shared dependency version
- Removed route contract
- Remote deployed before shell is compatible
Recommended solutions:
- Versioned contracts
- Contract tests
- Backward-compatible changes
- Deployment promotion checks
- Feature flags
- Version pinning
- Remote manifest governance
Independent deployment requires compatibility discipline.
16. Remote Loading Failures
Because remotes are loaded at runtime, they can fail.
Common causes:
- remoteEntry.js is unavailable
- CDN outage
- Network failure
- Wrong remote URL
- Remote deployed with bad bundle
- Shared dependency conflict
- Chunk loading error
- CORS issue
- Cache mismatch
| Bad Behavior Design | Good Behavior Design |
|---|---|
| Remote fails → full shell crashes | Remote fails → fallback UI appears. Shell remains usable. Error is logged with remote name and version |
Fallback example text: Cart is temporarily unavailable. Please refresh or try again later.
17. Error Boundary Strategy
Each remote should be wrapped with an error boundary.
Shell App
├── Product Remote
│ └── Error Boundary
├── Cart Remote
│ └── Error Boundary
└── Checkout Remote
└── Error BoundaryThe error boundary should capture: remoteName, remoteVersion, route, user action if available, error message, stack trace, and deployment version.
For critical flows like checkout, you may need stronger fallback strategies:
- Retry loading remote
- Redirect to stable fallback route
- Disable feature flag
- Rollback remote version
- Show support message
18. Lazy Loading Remotes
Do not load every remote upfront.
Bad setup example:
User opens homepage
Shell loads catalog
Shell loads cart
Shell loads checkout
Shell loads profile
Shell loads ordersGood setup example:
User opens homepage
Shell loads only required remotes
Cart remote loads when user visits /cart
Checkout remote loads when user visits /checkoutLazy loading improves initial load performance. But for critical paths, you can preload strategically.
Example: When a user adds an item to the cart, preload the checkout remote in the background to improve checkout transition speed.
19. Caching Strategy
Caching is tricky with Module Federation.
If remoteEntry.js is cached too aggressively, the shell may load old remote metadata. If chunks are not cached properly, performance suffers.
Common caching strategy:
- remoteEntry.js → short cache or versioned URL
- hashed chunks → long cache
- manifest/config → controlled cache
Example chunks hashing:
remoteEntry.js
main.8s7d9f.js
vendor.2a9sd1.jsHashed chunks can be cached long-term because the filename changes when content changes. The remote entry or manifest needs careful version control.
20. Deployment Models
There are multiple deployment models.
Latest Remote Model
shell → cart/latest/remoteEntry.js
Benefit: Simple, fast independent deployment.
Risk: A bad remote deploy can break the shell immediately.
Version-Pinned Model
shell → cart/1.4.2/remoteEntry.js
Benefit: Safer compatibility, controlled rollout.
Risk: Requires release coordination.
Manifest-Based Model
{
"cartApp": "https://cdn.company.com/cart/1.4.2/remoteEntry.js",
"productApp": "https://cdn.company.com/product/2.1.0/remoteEntry.js"
}Benefit: Flexible, supports rollback, and supports environment promotion.
This is often the best production approach for large systems.
21. Rollback Strategy
Rollback must be designed before production incidents.
If the cart remote version 1.5.0 breaks, you should be able to switch back to 1.4.2 quickly.
cartApp: 1.5.0 → broken
cartApp: 1.4.2 → stableRollback options include: revert remote deployment, update remote manifest, pin shell to older version, disable feature flag, or route traffic to stable remote.
Independent deployment is only safe when rollback is independent too.
22. Contract Testing
Contract testing verifies that host and remote still agree.
It can validate: exposed module exists, expected props are supported, event names are unchanged, event payload shape is compatible, route contract is stable, and shared dependency range is compatible.
Example contract payload validation:
CartPage must accept:
- userId
- locale
- currency
CartUpdated event must emit:
- itemCount
- cartIdIf the cart team changes this contract, CI should catch it before deployment. Without contract testing, runtime federation becomes risky.
23. E2E Testing
E2E tests validate full user journeys.
Example journeys:
- Search product → add to cart → checkout
- Login → view orders → reorder
- Open product page → change quantity → cart count updates
E2E tests catch issues across boundaries, such as routing bugs, remote loading failures, auth context issues, shared dependency conflicts, event communication bugs, and layout integration issues.
Do not rely only on unit tests. Micro frontend bugs often happen at integration points.
24. Observability
Module Federation requires per-remote observability.
Track metrics such as: remote load time, remote load failure, remote version, route where remote loaded, JavaScript errors by remote, chunk loading errors, Web Vitals by route, deployment health, and fallback UI frequency.
Useful log fields example:
{
"remoteName": "cartApp",
"remoteVersion": "1.4.2",
"route": "/cart",
"shellVersion": "2.0.1",
"userSessionId": "session_982a1s",
"errorType": "ChunkLoadError",
"chunkUrl": "https://cdn.company.com/cart/chunks/312.js"
}Good observability answers: Which remote failed? Which version failed? Which route failed? Was it a network issue or runtime issue? Did the problem start after deployment? How many users were affected?
25. Security Considerations
Module Federation loads code at runtime, so security matters.
Important concerns:
- Only load remotes from trusted origins.
- Use HTTPS.
- Apply strict CORS policies.
- Avoid exposing secrets in frontend config.
- Validate event payloads.
- Do not pass sensitive data through browser events.
- Use CSP where possible.
- Protect deployment pipelines.
A remote app is still executable JavaScript running inside the user’s browser. If a remote is compromised, the user experience can be compromised.
26. Common Anti-Patterns
Avoid these common federation anti-patterns:
| Anti-Pattern | Why It Is Bad |
|---|---|
| Sharing everything | Creates hidden coupling |
| Exposing internal modules | Breaks encapsulation |
| Loading all remotes upfront | Hurts performance |
| No fallback UI | Remote failure breaks product |
| No contract tests | Independent deployment becomes unsafe |
| Shell owns all domain logic | Shell becomes new monolith |
| Every team uses random dependency versions | Runtime instability |
| No version strategy | Rollback becomes difficult |
| Latest remote always in production | Higher blast radius |
| No observability | Debugging becomes guesswork |
27. Production Checklist
Before using Module Federation in production, ask:
- Do we have clear host and remote ownership?
- Are exposed modules stable and intentional?
- Are React and React DOM shared safely?
- Do we have a version strategy?
- Do we have contract tests?
- Do we have fallback UI for remote failures?
- Can we roll back one remote independently?
- Are remote load errors monitored?
- Are Web Vitals tracked per route?
- Is remoteEntry.js caching configured carefully?
- Are remotes loaded only from trusted origins?
- Do we avoid sharing business internals?
If these are missing, the implementation may work locally but fail operationally.
28. Interview Questions
Q1. What is Module Federation?
Module Federation is a webpack 5 feature that allows one application to expose modules and another application to consume them at runtime. It is useful for micro frontends because independently built apps can be composed without rebuilding the host every time.
Q2. What is the difference between host and remote?
The host is the consuming application, usually the shell. The remote is the application that exposes modules. The host loads remote modules at runtime through the remote entry file.
Q3. What is remoteEntry.js?
remoteEntry.js is the runtime manifest generated by the remote. It tells the host what modules are exposed and how to load the remote chunks.
Q4. Why do we share React as a singleton?
React should usually be shared as a singleton to avoid loading multiple React instances. Multiple React instances can cause issues with hooks, context, and bundle size.
Q5. What are the risks of Module Federation?
The main risks are runtime loading failures, version mismatches, shared dependency conflicts, caching issues, and harder debugging. These risks can be reduced with fallback UI, contract testing, versioned manifests, rollback strategy, and observability.
Q6. How do you handle remote failure?
Wrap each remote with an error boundary, show fallback UI, log the error with remote name and version, and support retry or rollback for critical flows.
Q7. How do you safely deploy remotes independently?
Use versioned contracts, CI checks, contract testing, feature flags, environment promotion, release health monitoring, and rollback support.
Q8. What should not be exposed from a remote?
Internal reducers, private components, unstable utilities, and domain implementation details should not be exposed. A remote should expose stable public modules only.
29. Strong Senior Answer
If an interviewer asks: "How would you use Module Federation in a large e-commerce frontend?"
A strong answer:
I would use a shell app as the host and domain-specific remotes for catalog, cart, checkout, orders, and profile. The shell would own global layout, top-level routing, authentication bootstrap, and remote loading. Each remote would own its domain UI and business logic. I would use Module Federation to load remotes at runtime, but I would not treat it as just a component-sharing tool. I would design around production concerns: shared dependency governance, singleton React, contract testing, fallback UI, versioned remote manifests, rollback, and per-remote observability. For state, I would avoid a giant shared store. Cart and checkout state should be backend-driven, with small explicit events only where needed. The goal is independent team deployment with a consistent and reliable user experience.
30. Summary
Module Federation is powerful because it allows independently built frontend applications to compose at runtime.
It enables: independent deployment, runtime composition, team autonomy, domain-owned frontend apps, and flexible micro frontend architecture.
But it also introduces: runtime failure risk, dependency version complexity, caching challenges, contract compatibility issues, observability needs, and rollback requirements.
The best engineers do not just say "Use Module Federation." They explain how to use it safely in production.
Module Federation gives you runtime composition, but production readiness comes from contracts, versioning, fallback UI, rollback, and observability.
References
- webpack Module Federation Documentation (https://webpack.js.org/concepts/module-federation/)
- Module Federation Official Site (https://module-federation.io)
- Micro Frontends (https://micro-frontends.org)
- Micro Frontends — Martin Fowler (https://martinfowler.com/articles/micro-frontends.html)
- AWS Prescriptive Guidance: Micro-frontends (https://docs.aws.amazon.com/prescriptive-guidance/latest/micro-frontends-aws/introduction.html)