Micro Frontends at Scale: Breaking the Monolith UI
Your frontend started as a clean React app. Two years later it's a 400-component monolith where changing a button in checkout breaks the product catalog. Sound familiar?
Micro frontends apply the same decomposition principles we use in backend microservices — but to the UI layer. Here's the architecture that actually works in production.
The Problem with Monolith Frontends
Every team shares one build, one deploy pipeline, one package.json with 300 dependencies. A version bump in the catalog team's charting library blocks the checkout team's hotfix.
The Micro Frontend Architecture
Each micro frontend (MFE) is an independently built and deployed unit. The App Shell handles top-level routing and authentication, while each MFE owns its own domain, dependencies, and release cycle.
Integration Patterns
There are three main ways to compose micro frontends at runtime:
1. Build-Time Integration (npm packages)
Each MFE is published as a package. Simple but defeats the purpose — you still need a coordinated build.
2. Runtime Integration via Module Federation
This is the most popular approach today. Webpack 5's Module Federation lets the host app dynamically load remote modules at runtime. Each remote exposes components through a remoteEntry.js manifest.
3. Server-Side Composition
Shared State: The Hard Part
The biggest mistake teams make is sharing too much state. Here's the pattern that works:
Use Custom Events (or a lightweight pub/sub) for cross-MFE communication. Only share truly global concerns like authentication tokens and locale settings. Each MFE owns its own domain state.
When NOT to Use Micro Frontends
The Decision Framework
Before decomposing, ask: "Can two teams work on this independently for a sprint without coordination?" If yes, it's a good boundary. If no, keep it together.
Micro frontends aren't about technology. They're about organizational scalability. The architecture follows the team structure — Conway's Law in action.