At Google, with hundreds of frontend engineers, monolithic SPAs don't scale organizationally. Microfrontends let teams ship independently.
What Are Microfrontends?
The microservices approach applied to the frontend. Each team owns a vertical slice — from UI to API — and deploys independently.
Integration Approaches
1. Build-Time Integration
Each micro-app is an npm package consumed by a shell app. Simple but creates deployment coupling.
2. Runtime Integration via iframes
Complete isolation but poor UX (no shared routing, styling, or state).
3. Module Federation (Webpack 5)
// Host app webpack config
new ModuleFederationPlugin({
remotes: {
checkout: "checkout@https://checkout.example.com/remoteEntry.js",
catalog: "catalog@https://catalog.example.com/remoteEntry.js"
}
});
// In host app code
const Checkout = React.lazy(() => import("checkout/CheckoutPage"));4. Web Components
Framework-agnostic integration. Each team ships custom elements that the shell app composes.
Shared Concerns
- Routing: Shell app owns top-level routes, delegates sub-routes to micro-apps
- Styling: Use CSS custom properties for theming, CSS modules or Shadow DOM for isolation
- State: Use custom events or a shared event bus. Avoid shared global state.
- Auth: Shell app handles auth, passes tokens down
When NOT to Use
- Small teams (< 5 developers)
- Simple applications with few features
- When teams don't need independent deployment
- When the added complexity outweighs the benefits
Performance Considerations
Each micro-app bundle adds to the total JS. Shared dependencies (React, lodash) should be loaded once using Module Federation's shared config or import maps.