Micro Frontend Architecture: Past and Present
Micro frontends are an architectural pattern that brings microservices concepts to frontend development. It splits a large frontend application into multiple independently developed and deployed small applications, allowing each team to independently own their business domain and choose their own tech stack. This concept was first proposed by ThoughtWorks in 2016 and quickly gained adoption in large enterprises.
According to the 2025 State of Micro Frontends survey, over 43% of mid-to-large enterprises are already using micro frontend architecture in production, with e-commerce platforms, enterprise management systems, and SaaS products being the most common use cases. The core value of micro frontends lies in solving the problems that arise as monolithic frontend applications grow in scale, such as declining development efficiency, deployment coupling, and team collaboration difficulties.
1. Core Challenges of Micro Frontends
1.1 Technology Selection Dimensions
| Solution | Communication Mechanism | Isolation | Shared Dependencies | Learning Cost |
|---|---|---|---|---|
| iframe | postMessage | Strongest | Cannot share | Lowest |
| Web Components | Custom Events | Strong | Limited sharing | Medium |
| Module Federation | Runtime loading | Medium | Full sharing | Medium-High |
| Single-SPA | Route distribution | Medium | Limited sharing | High |
| qiankun | Sandbox isolation | Strong | Limited sharing | Medium |
1.2 Applicable Scenarios
- Large admin/backend systems: Multiple business lines iterate independently, avoiding deployment conflicts
- Multi-team collaboration projects: Each team independently owns feature modules
- Gradual migration: Old systems progressively refactored, coexisting with new during transition
- Multi-tech stack coexistence: Different teams using different frameworks (React/Vue/Angular)
2. Major Implementation Solutions
2.1 Module Federation (Webpack 5)
Module Federation is a micro frontend solution built into Webpack 5, allowing one JavaScript application to dynamically load code modules from another application at runtime.
// Host application configuration
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
app2: 'app2@http://localhost:3002/remoteEntry.js',
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true },
},
}),
],
};
The "child app" side declares its exposes in webpack so its modules are available to others:
// Remote app configuration
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
exposes: {
'./ProductList': './src/ProductList',
'./Cart': './src/Cart',
},
shared: { react: { singleton: true }, 'react-dom': { singleton: true } },
})
Once the browser loads remoteEntry.js, the host can use the remote's modules on demand via import('app1/ProductList'); shared dependencies load only once through shared, avoiding a duplicated React instance.
2.2 qiankun (Based on Single-SPA)
qiankun is an open-source micro frontend framework from Ant Group, built on Single-SPA, providing out-of-the-box sandbox isolation and application lifecycle management.
import { registerMicroApps, start } from 'qiankun';
registerMicroApps([
{
name: 'react-app',
entry: '//localhost:7100',
container: '#subapp-container',
activeRule: '/react',
},
{
name: 'vue-app',
entry: '//localhost:7200',
container: '#subapp-container',
activeRule: '/vue',
},
]);
start({ sandbox: { experimentalStyleIsolation: true } });
2.3 The iframe Approach
Although iframes are often dismissed as "outdated," they offer the strongest isolation, making them suitable for integrating untrusted third-party content or fully independent subsystems.
| Solution | Complexity | Performance | Maintainability | Best for |
|---|---|---|---|---|
| Module Federation | Medium | High | High | Mid-to-large projects, same stack |
| qiankun | Medium | High | Medium | Mid-to-large projects, multiple stacks |
| iframe | Low | Low | High | Third-party integration, strong isolation |
| Web Components | High | Medium | Medium | Cross-framework component sharing |
Iframes talk to the host via postMessage, which suits cross-origin, strongly isolated scenarios:
// Host sends a message to the iframe
frame.contentWindow.postMessage({ type: 'theme', value: 'dark' }, '*');
// Inside the iframe, listen for it
window.addEventListener('message', (e) => {
if (e.data?.type === 'theme') document.documentElement.dataset.theme = e.data.value;
});
The trade-off is that async messages are the only communication path, which makes complex state sync tedious; for third-party content that only needs to render, iframe remains the least-friction option.
3. Key Implementation Points
3.1 Style Isolation
- Use CSS Modules or styled-components to avoid style conflicts
- Set CSS namespace prefixes
- Use Shadow DOM for true isolation
3.2 State Management
- Cross-application communication via custom events
- Use shared stores (e.g., multiple Redux store instances)
- Pass simple state via URL parameters
3.3 Performance Optimization
- Extract common dependencies as shared modules
- Load sub-applications on demand, avoid loading too many on first screen
- Preload sub-applications with high access probability
3.4 A Gradual Migration Case
Take an existing e-commerce admin as an example; a full migration roughly has four steps: first, extract the business-agnostic infrastructure (login, permissions, routing shell) into a host; second, pick a module that is independent and changes frequently (such as the order list) as the first child app to validate the flow; third, migrate the remaining modules business line by business line; finally, freeze the old monolith and only keep compatibility for the old and new entry points. The whole process does not need a "big bang" rewrite — old features keep working while new ones land incrementally.
A useful rule of thumb: when two teams' release cadences start blocking each other, or the monolith build time exceeds 10 minutes, that is usually the signal to introduce micro frontends (at least split out child apps). Conversely, a team of two or three people with deeply coupled modules is better served by modularization or route-level splitting first.
Common Questions
How is a micro frontend different from a component library? A component library shares UI units reusable within one app; a micro frontend shares complete apps that can be developed and deployed independently. The former solves "code reuse," the latter solves "organizational collaboration and independent releases."
How do child apps share a login state? Let the host own authentication and pass tokens to children via URL, localStorage, or custom events; SSO solutions (such as OIDC) usually also live at the host layer.
Will micro frontends slow down first paint? Not if handled well. Put common dependencies in shared, lazy-load children by route, and preload high-probability modules — first paint typically costs just one extra remoteEntry.js request.
4. Summary
Micro frontend architecture provides an effective organizational approach for large frontend projects, enabling multi-team independent development and deployment. When choosing a solution, consider team tech stack, project scale, and isolation requirements. It's recommended to start with Module Federation or qiankun, as they have mature ecosystems and active communities. Remember, the purpose of architecture is to solve problems, not create them — only introduce micro frontends when truly needed.
Reference: Webpack Module Federation docs https://webpack.js.org/concepts/module-federation/; qiankun official docs https://qiankun.umijs.org/; ThoughtWorks micro frontends tech radar https://www.thoughtworks.com/radar/techniques/micro-frontends