Skip to main content
Micro-frontends

Micro-frontends Overview

Estimated Time: 3 hours | Difficulty: Advanced | Prerequisites: Routing, Lazy Loading, Build Process
Micro-frontends extend the microservices concept to the frontend, allowing teams to build and deploy parts of a web application independently. The analogy works well: just as a backend might have separate services for auth, payments, and inventory that communicate via APIs, a micro-frontend architecture lets separate teams own separate sections of the UI — each with its own repo, build pipeline, and deployment schedule. A word of caution: Micro-frontends solve an organizational problem (team autonomy at scale), not a technical one. If you have a single team building a single product, micro-frontends add significant complexity for zero benefit. The sweet spot is organizations with 3+ teams that need to ship features independently without coordinating releases.

Module Federation Setup

Using @angular-architects/module-federation

Host (Shell) Configuration

Remote Configuration


Dynamic Remote Loading

Static remote configuration (hardcoded URLs in webpack config) works for development but fails in production where remote URLs differ per environment. Dynamic remote loading solves this by fetching the MFE registry at runtime — typically from a backend API or a configuration file. This means you can add, remove, or update micro-frontends without rebuilding and redeploying the shell application. Think of it like a TV with a channel guide: the TV (shell) does not need to know about every channel at manufacturing time. It downloads the channel list on startup, and new channels can appear without replacing the TV.

Shared State & Communication

Shared State Service

Cross-MFE state is the hardest problem in micro-frontend architecture. The temptation is to use a global NgRx store, but that creates tight coupling — the very thing micro-frontends are designed to avoid. The better approach is a minimal shared state service that only holds truly global data (authenticated user, theme, shopping cart) while each MFE manages its own feature state internally.
Pitfall: Do not put feature-specific state in the shared state service. If the “products” MFE needs filter state, that belongs in the products MFE, not in shared state. The rule: if only one MFE reads it, it is not shared state.

Event Bus for Cross-MFE Communication

An event bus decouples micro-frontends by enabling publish/subscribe communication. The products MFE does not need to know that the header MFE exists — it just emits a “cart:itemAdded” event, and anyone who cares can listen. This is the same pattern as browser DOM events (a button does not know who is listening to its click), applied at the application architecture level.
Practical tip: Always include a source field in your events so you can debug which MFE emitted what. In production, log events with timestamps to reconstruct the sequence of cross-MFE interactions when debugging issues.

Shared UI Library


Deployment Strategy


Best Practices

Share Wisely

Only share what’s necessary - over-sharing leads to coupling

Version Compatibility

Test shared dependency versions across all MFEs

Consistent Styling

Use a shared design system with CSS custom properties

Error Boundaries

Isolate MFE failures to prevent cascade effects

Next: Nx Monorepo

Scale your Angular projects with Nx monorepo tooling