The Micro-Frontend Architecture Handbook
Over the years, in my role as a lead full-stack developer, solutions architect, and mentor, I’ve been immersed in the world of micro frontend architecture, working across different large-scale frontend projects where multiple teams, stacks, and deplo...

Over the years, in my role as a lead full-stack developer, solutions architect, and mentor, I’ve been immersed in the world of micro frontend architecture, working across different large-scale frontend projects where multiple teams, stacks, and deployment pipelines had to coexist somehow.
As projects grew in complexity and teams worked in parallel across different stacks, it became clear that monolithic approaches couldn’t keep up. I needed practical tools that allowed easy cross-app interaction, independent deployability, better team autonomy, framework-agnosticism, and more. Some solutions worked elegantly in theory but struggled in real-world conditions. Others made things messier and more painful than helpful.
After diving deep into different paradigms—from iframes to Web Components, single-spa, Module Federation, Piral, Luigi, and hybrid setups—I even distilled my proven experience into a full-fledged online course on Udemy.
And today, in this comprehensive hands-on tutorial, I want to share my expertise and tell you more about micro-frontend architecture—method by method—with code, tradeoffs, visuals, and real-world insights.
Table of Contents
What are Micro Frontends For?
In traditional frontend development, we often build single, monolithic apps—one codebase, one repo, one deployment pipeline, one team. It works great for small to medium projects, sometimes even for larger ones.
But challenges arise when:
Your frontend codebase expands beyond 50+ components.
Multiple development teams need autonomy over different parts and tech stacks.
Different sections require varying deployment frequencies (weekly or monthly).
You need to integrate diverse frameworks, like combining React features with an Angular-based CMS.
This is where micro frontends step in.
Micro frontends extend the principles of microservices to the frontend world. Instead of one big frontend app, you build independent frontend modules, each owned by a team, using its own tech stack, deployed separately, and integrated at runtime.
Think of it like Lego blocks:
Each block is similar to a self-contained micro frontend.
They plug into a shared layout or shell.
Each can evolve, update, or be replaced without affecting the others.
For example, imagine that you’re building a modern e-commerce site, and here’s what your business side expects from you:
Section | Team | Stack | Deployment |
Product Listing | Search Team | React | Weekly |
Product Details | Catalog Team | Angular | Monthly |
Cart & Checkout | Checkout Team | Vue | Biweekly |
CMS Pages | Marketing Team | Vanilla JS | Daily |
Each team wants autonomy, and with micro frontends, each of these sections becomes a separate app, loaded dynamically into a shell at runtime.
Why It’s Getting Popular?
Here are a few things everyone considers:
Independent deployments – A little or no effort to coordinate every release.
Team autonomy – Teams choose their own stack and tools on the project.
Incremental upgrades – Migrate legacy apps piece by piece incrementally without the need to rewrite the whole app at once.
Technical agnosticism – Vue, React, Angular? Doesn’t matter. They can all work together seamlessly at the same time in a single app.
Better scalability – Parallelize work across teams to enable efficiency of delivery and scale at ease.
Now let’s discover how we can bring this idea to life in our projects.
Nowadays, there are different ways to achieve that, but not all solutions are equal. The implementation method you choose will drastically affect:
Developer experience
Bundle sizes and performance
SEO and accessibility
Runtime stability
Interoperability across stacks
So let’s begin by exploring the oldest, but still surprisingly viable method.
Method #1: Iframes & Cross-Window Messaging
You may ask, “Aren’t iframes bad?” They’re often misunderstood. While yes, iframes can feel clunky and isolated, they’re also the most secure and decoupled way to host micro frontends—especially when you don’t trust the team on the other side.
What Is an IFRAME?
An iframe (inline frame) is an HTML element that allows you to embed another HTML page within your current webpage. The whole communication between apps is strictly based on events and delivered by means of the Post Message API.
If you need to send data to another app, you simply call the postMessage()
method on that element. On the other side, to receive a message, you just have to subscribe to the message
event. That’s it.
Real-World Example
Let’s see a simple example of two apps communicating with each other using iframes
on two apps:
The Main Web App
A Search App.
Every iframe must be hosted somewhere to serve static content from it. It can be AWS Amplify, Digital Ocean, Heroku, GitHub Pages, or alike.
To help you out here, here’s an official GitHub guideline explaining how to host a website on their platform.
Let’s say you deployed a Search App on Github Pages and you were given this URL to host your app: https://example.github.io
. Now let’s write some content for it.
Assuming that you want to post messages from the Search App to the Main Web App, and to subscribe to the incoming messages from it there. You can do it in this way:
console.log('Initializing Search App...');
// Subscribe to messages from outside the iframe (like Main Web App)
window.addEventListener('message', (event) => {
if (event.data?.type === 'init') {
console.log('Main Web App passed userId:', event.data.userId);
}
});
// Simulate sending Search results back to Main Web App
window.parent.postMessage({
type: 'searchResult',
payload: ['Item A', 'Item B']
}, '*');
Here, you initialize the search app and set up two-way communication with a parent application (such as a main web app) using the Post Message API. You listen for incoming messages using the built-in message
event. Once received, that message becomes available in the event.data
object. Finally, you simulate sending data back to the parent by posting a searchResult
message containing a list of items. This setup enables isolated iframe-based apps to communicate safely with the main shell application.
Then, in the DOM of the main web app, you need to include the iframe that will render the search app, specifying the URL to the hosted search app in this way:
<iframe
id="search-mfe"
src="https://example.github.io"
style="width: 100%; height: 200px; border: none;"
>iframe>
Styles were added here to ensure that the iframe
displays seamlessly within the layout for a cleaner UI integration.
And now you can pass some content from the main web app down to the search app and get some messages from it. You can accomplish it in the main web app’s JavaScript code in this way:
console.log('Initializing Main Web App...');
const iframe = document.getElementById('search-mfe');
iframe.onload = () => {
// Send message to child iframe (inputs)
iframe.contentWindow.postMessage({ type: 'init', userId: 42 }, '*');
};
window.addEventListener('message', (event) => {
// Receive data from the Search App (outputs)
if (event.data?.type === 'searchResult') {
console.log('Received result from Search App: ', event.data.payload);
}
});
As you see, when the iframe
loads, the init
event is sent to the search app (the type
can be anything you want, just ensure it matches the one that another app expects from you). And then, in the message
event handler as before, you can receive the incoming messages from the search app, and do something with them.
Here are a few pros and cons to consider, along with popular use cases:
✅ Pros:
Strong sandboxing: No shared memory, no shared styles.
Zero dependency clashes: One iframe is equivalent to one environment.
Perfect for legacy: Easy to wrap old apps in an iframe.
Practical for micro-apps in PHP, Java, Razor (ASP.NET)
❌ Cons:
Slow rendering
Difficult shared navigation
Inconsistent/complicated styling
Complex communication
Must be hosted somewhere