Micro-Frontends
Scale frontend development across teams with micro-frontends - Module Federation, composition strategies, shared dependencies, and team contracts.
skill: Micro-Frontends category: Frontend tags: [Micro-Frontends, Module Federation, Architecture, Monorepo, Team Autonomy] readingTime: 6
Micro-frontends solve an organizational problem, not a technical one. They let multiple teams deploy frontend features independently, without coordinating releases. The technical complexity (shared state, routing, dependencies) is the cost. Only adopt when team size and coupling genuinely demand independent deployment - micro-frontends in a single-team project are over-engineering.
Workflow
- Understand composition strategiesMicro-frontends can be composed at different layers - build time (npm package), server (SSI, edge), or client (Module Federation, Web Components, iframes). Each trades different costs.
- Configure Webpack Module FederationModule Federation lets applications import components from other deployed applications at runtime - Team A deploys independently, Team B (host) loads Team A's components live.
- Share state across micro-frontendsMicro-frontends need to share auth state, cart data, and routing without tight coupling. Shared state via custom events or shared store is the pattern.
- Handle routing in micro-frontendsEach micro-frontend may have its own internal router. The host must coordinate which micro-frontend owns which URL prefix without conflicts.
- Define team contracts and contracts testingIndependent deployment only works if teams agree on contracts (API shape, event names, component props). Breaking changes in a remote crash the host.
Output Format
Micro-frontends: Module Federation with singleton React, custom event bus for state, MemoryRouter in remotes, host routing by URL prefix, and Pact contract testing.
Remote: exposes + shared (react singleton)
Host: remotes + lazy(() => import("teamA/Component"))
State: window.dispatchEvent(CustomEvent) + addEventListener
Routing: host BrowserRouter, remotes MemoryRouter
Contracts: Pact consumer-driven + semantic versioningExamples
Edge Cases & Gotchas
- Remote is unavailable - If a remote fails to load, the host crashes (lazy import rejection). Wrap in an error boundary to fail gracefully: <ErrorBoundary fallback={<Fallback />}>.
- CSS conflicts - Without Shadow DOM, CSS from different micro-frontends can collide. Use CSS Modules, BEM with team prefix, or CSS-in-JS to scope styles. Never use global CSS class names.
- Bundle size explosion - Module Federation can duplicate dependencies if shared config mismatches between host and remote. Audit bundle sizes after adding remotes.
- Cross-origin security - Module Federation loads JS from other origins - this is XSS risk if remotes are compromised. Limit to same-organization domains with proper CSP.
When to Break These Rules
- Use a monorepo (Nx, Turborepo) with shared packages instead of micro-frontends for small-to-medium teams - monorepos provide independence without runtime complexity.
- Use micro-frontends only when you have independent teams deploying at genuinely different cadences - the overhead isn't worth it for coordinated releases.
Reference Files
https://module-federation.io/https://martinfowler.com/articles/micro-frontends.html